{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4f0ef1f2-0c73-4ef5-b430-48fe4ce450c0",
   "metadata": {},
   "source": [
    "<div style=\"text-align: right\" align=\"right\"><i>Peter Norvig<br>December 2024</i></div>\n",
    "\n",
    "# Advent of Code 2024\n",
    "\n",
    "I  enjoy doing the [**Advent of Code**](https://adventofcode.com/) (AoC) programming puzzles, so here we go for 2024! This is the 10th year, so congratulations to puzzle creator [**Eric Wastl**](https://adventofcode.com/2024/about). Our old friend [**Gary Grady**](https://find.sciences.social/search/accounts/@garygrady@mastodon.social) is here to provide illustrations:\n",
    "\n",
    "<a href=\"https://mastodon.social/@garygrady\"><img src=\"https://pbs.twimg.com/media/Gdp709FW8AAq2_m?format=jpg&name=medium\" width=400 alt=\"GaryJGrady cartoon\"></a>\n",
    "\n",
    "Even before December 1st I can start by loading up my [**AdventUtils.ipynb**](AdventUtils.ipynb) notebook (same as last time except for the `current_year`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ed82ed5b-a42d-468b-8f6e-288d3c2de20b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.12.7 | packaged by Anaconda, Inc. | (main, Oct  4 2024, 08:22:19) [Clang 14.0.6 ]\n"
     ]
    }
   ],
   "source": [
    "%run AdventUtils.ipynb\n",
    "current_year = 2024\n",
    "\n",
    "print(sys.version)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dfecffd7-6955-45ba-9dc2-1ec805baba85",
   "metadata": {},
   "source": [
    "Each day's solution consists of these parts, making use of my `parse` and `answer` utilities:\n",
    "- **Reading the input**: Parse the input file with, e.g. `pairs = parse(1, ints)`. \n",
    "- **Solving Part One**: Find the solution and record it with, e.g., `answer(1.1, 4, lambda: 2 + 2)`.\n",
    "- **Solving Part Two**: Find the solution and record it with, e.g., `answer(1.2, 9, lambda: 3 * 3)`.\n",
    "- *(Optional Part Three: On some days, I'll add some further exploration, visualization, or verification.)*\n",
    "\n",
    "The function `parse` assumes that the input is a sequence of sections (default one per line), each of which should be parsed in some way and then returned as a tuple.  The parsing method  `ints` says to treat each section as a tuple of integers. The function `answer` checks that the correct answer is computed (useful for regression testing), and records the run time (that's why a `lambda:` is used). You can read the [**AdventUtils.ipynb**](AdventUtils.ipynb) notebook for more on these functions (and the other utilities used throughout this notebook, such as the `Grid` class).\n",
    "\n",
    "To fully understand each day's puzzle, and to follow along the drama involving Santa, the elves, the reindeer, some elephants, the Chief Historian, and all the rest, you need to read the puzzle descriptions on the [**AoC**](https://adventofcode.com/) site, as linked in the header for each day's solutions (e.g. [**Day 1**](https://adventofcode.com/2023/day/1) below).  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c6120a1-3129-44ff-935c-30c1d81ae028",
   "metadata": {},
   "source": [
    "# [Day 1](https://adventofcode.com/2024/day/1) Historian Hysteria\n",
    "\n",
    "According to the narrative, North Pole Historians created two lists of **location IDs**. We can parse them as a sequence of pairs of integers, and then use the transpose function, `T`, from my [AdventUtils](AdventUtils.ipynb) to get two tuples of ID numbers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "22e5d621-a152-4712-866f-f8b962b5dd14",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1000 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "38665   13337\n",
      "84587   21418\n",
      "93374   50722\n",
      "68298   57474\n",
      "54771   18244\n",
      "49242   83955\n",
      "66490   44116\n",
      "65908   51323\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 1000 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(38665, 13337)\n",
      "(84587, 21418)\n",
      "(93374, 50722)\n",
      "(68298, 57474)\n",
      "(54771, 18244)\n",
      "(49242, 83955)\n",
      "(66490, 44116)\n",
      "(65908, 51323)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "left, right = T(parse(1, ints))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63cf2940-e251-49e4-8bc9-f1bcd599f8f4",
   "metadata": {},
   "source": [
    "<img src=\"https://pbs.twimg.com/media/GdvPVOpXcAEZ34_?format=jpg&name=medium\" width=400>\n",
    "\n",
    "### Part 1: What is the total distance between your lists?\n",
    "\n",
    "The **distance** between two numbers is defined as the absolute value of their difference, and the **total distance** between two lists is the sum of the distances between respective pairs, where \"respective\" means to sort each list and then take the distance between the first element of each list, plus the distance between the second element of each list, and so on. (I use the transpose utility function, `T`, to turn the input sequence of 1000 pairs into two lists, each of 1000 integers.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "8d6bc9f5-5fa1-4dad-bd43-d957833d8ea9",
   "metadata": {},
   "outputs": [],
   "source": [
    "def total_distance(left: Ints, right: Ints) -> int:\n",
    "    \"\"\"Total distance between respective list elements, after sorting.\"\"\"\n",
    "    return sum(abs(a - b) for a, b in zip(sorted(left), sorted(right)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6ada5e5b-2fb7-4198-a5bb-7b2af4b9270a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  1.1:   .000 seconds, answer 1830467           ok"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(1.1, 1830467, lambda:\n",
    "       total_distance(left, right))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88e26234-f1d2-4a62-86b0-2ad9251215eb",
   "metadata": {},
   "source": [
    "### Part 2: What is their similarity score?\n",
    "\n",
    "The **similarity score** is defined as the sum of each element of the left list times the number of times that value appears in the right list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "0131e096-38d1-4c13-9e9c-b0d09839a5cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "def similarity_score(left: Ints, right: Ints) -> int:\n",
    "    \"\"\"The sum of each x in `left` times the number of times x appears in `right`.\"\"\"\n",
    "    counts = Counter(right)\n",
    "    return sum(x * counts[x] for x in left)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "6f6c298a-53a1-4d80-8747-7dd713d4d4f0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  1.2:   .000 seconds, answer 26674158          ok"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(1.2, 26674158, lambda:\n",
    "       similarity_score(left, right))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b895bb80-2269-423f-a33c-abaa3d96561a",
   "metadata": {},
   "source": [
    "As usual, the first day is something of a warm-up, coding up a solution is easy, and both parts run in under a millisecond (I don't need to know anything more precise than that)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9fa4fe0-4194-47d7-b815-b571af98caee",
   "metadata": {},
   "source": [
    "# [Day 2](https://adventofcode.com/2024/day/2): Red-Nosed Reports\n",
    "\n",
    "Today's input is a sequence of engineering safety **reports**, each of which consists of a sequence of integers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "10e1ab83-a6ec-4143-ad9a-eaae220adcde",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1000 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "74 76 78 79 76\n",
      "38 40 43 44 44\n",
      "1 2 4 6 8 9 13\n",
      "65 68 70 72 75 76 81\n",
      "89 91 92 95 93 94\n",
      "15 17 16 18 19 17\n",
      "46 47 45 48 51 52 52\n",
      "77 78 79 82 79 83\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 1000 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(74, 76, 78, 79, 76)\n",
      "(38, 40, 43, 44, 44)\n",
      "(1, 2, 4, 6, 8, 9, 13)\n",
      "(65, 68, 70, 72, 75, 76, 81)\n",
      "(89, 91, 92, 95, 93, 94)\n",
      "(15, 17, 16, 18, 19, 17)\n",
      "(46, 47, 45, 48, 51, 52, 52)\n",
      "(77, 78, 79, 82, 79, 83)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "reports = parse(2, ints)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5dfd72c2-06c6-4c71-ae37-0c2c84074091",
   "metadata": {},
   "source": [
    "### Part 1: How many reports are safe?\n",
    "\n",
    "A report is **safe** if it is monotonically strictly increasing or strictly decreasing, and if no jump between adjacent numbers is greater than 3 in absolute value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "0f6b6744-e93d-47cf-accd-daab9f3650d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_safe(report: Ints) -> bool:\n",
    "    \"\"\"A report is safe if all adjacent-number-jumps are either in {1, 2, 3} or in {-1, -2, -3}.\"\"\"\n",
    "    jumps = set_of_jumps(report)\n",
    "    return jumps.issubset({1, 2, 3}) or jumps.issubset({-1, -2, -3})\n",
    "    \n",
    "def set_of_jumps(numbers: Ints) -> Set[int]:\n",
    "    \"\"\"The set of differences between adjacent numbers.\"\"\"\n",
    "    return {numbers[i] - numbers[i - 1] for i in range(1, len(numbers))}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5625ad98-f571-4451-ad19-8614833dfb10",
   "metadata": {},
   "source": [
    "Here are examples of how these functions work:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "c0cc052b-e9ef-4757-a860-4cd34dd00fb8",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert set_of_jumps((7, 6, 4, 2, 1)) == {-1, -2}\n",
    "assert is_safe((7, 6, 4, 2, 1))  == True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "051c71b7-4375-4812-b7cc-0c50adf20a09",
   "metadata": {},
   "source": [
    "And here is the answer to the puzzle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "e662bf10-4d6a-40f1-95ce-dfc39f5b3fc2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  2.1:   .000 seconds, answer 257               ok"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(2.1, 257, lambda:\n",
    "       quantify(reports, is_safe))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee48bf63-8a67-407b-9a73-df097811eabc",
   "metadata": {},
   "source": [
    "Note: I used my [AdventUtils](AdventUtils.ipynb) function `quantify` (adapted from the [itertools recipes](https://docs.python.org/3/library/itertools.html#itertools-recipes)). `quantify(reports, is_safe)` counts the number of items in `reports` for which `is_safe` is true.\n",
    "\n",
    "### Part 2: How many reports are safe using the Problem Dampener?\n",
    "\n",
    "The **problem dampener** says that a report is safe if there is some way to drop one number and get a safe report. So I'll generate all ways of dropping one number and check each one for safety."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "6c78f864-5425-472f-9740-6f44650a98ca",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_safe_with_dampener(report: Ints) -> bool:\n",
    "    \"\"\"Is there any way to drop one element of `report` to get a safe report?\"\"\"\n",
    "    return any(map(is_safe, drop_one(report)))\n",
    "\n",
    "def drop_one(seq: Sequence) -> Iterable[Sequence]:\n",
    "    \"\"\"All ways of dropping one element of the input sequence.\"\"\"\n",
    "    return (seq[:i] + seq[i + 1:] for i in range(len(seq)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "7f492898-a704-4fb4-a93f-824f655d1f51",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert set(drop_one('1234')) == {'234', '134', '124', '123'}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "d1b9ffb5-af7a-465f-a063-c31df2d0605c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  2.2:   .002 seconds, answer 328               ok"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(2.2, 328, lambda:\n",
    "       quantify(reports, is_safe_with_dampener))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54d6a0c2-a8ed-404d-abc0-72aa28a49f5d",
   "metadata": {},
   "source": [
    "# [Day 3](https://adventofcode.com/2024/day/3): Mull It Over\n",
    "\n",
    "Today's input is a computer program with some corrupted characters. The program has multiple lines, but newlines don't matter in this programming language, so I will concatenate them into one big string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "78080200-0f9f-4492-9bee-c936737ee96f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 6 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "where(536,162)~'what()what()how(220,399){ mul(5,253);mul(757,101)$where()@why()who()&when()from( ...\n",
      "}?~who()select()-mul(316,505)&%*how()mul(363,589)>?%-:)where()~{{mul(38,452)select()%>[{]%>%mul( ...\n",
      "?>where(911,272)'mul(894,309)~+%@#}@#why()mul(330,296)what()mul(707,884)mul;&}<{>where()$why()]m ...\n",
      "> (when()[where()/#!/usr/bin/perl,@;mul(794,217)select():'])select()mul(801,192)why()&]why()/:]* ...\n",
      ",+who():mul(327,845)/ >@[>@}}mul(86,371)!~&&~how(79,334)mul(637,103)why()mul(358,845)-#~?why(243 ...\n",
      "where()#{*,!?:$mul(204,279)what()!{ what()mul(117,94)!select()>:mul(665,432)#don't()!!<!? mul(50 ...\n"
     ]
    }
   ],
   "source": [
    "program = cat(parse(3))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5327e631-502f-4687-83d5-84a4e4012ccf",
   "metadata": {},
   "source": [
    "<a href=\"https://x.com/garyjgrady\"><img src=\"https://pbs.twimg.com/media/Gd5ZSI9XEAAAzQh?format=jpg&name=small\" width=400 alt=\"GaryJGrady cartoon\"></a>\n",
    "\n",
    "\n",
    "### Part 1: What do you get if you add up all of the results of the multiplications?\n",
    "\n",
    "For Part 1, just look for instructions of the form \"mul(*digits*,*digits*)\", using a regular expression and `re.findall`. Perform each of these multiplications and add them up, and ignore all other characters/instructions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "bf6366b1-6952-47d8-8b3c-09f8d05ec093",
   "metadata": {},
   "outputs": [],
   "source": [
    "def execute(program: str) -> int:\n",
    "    \"\"\"The sum of the results of the multiply instructions.\"\"\"\n",
    "    return sum(prod(ints(m)) for m in all_multiplications(program))\n",
    "\n",
    "all_multiplications = re.compile(r'mul\\(\\d+,\\d+\\)').findall"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "2032c903-5f23-4c16-ba68-410b6c1750e1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  3.1:   .001 seconds, answer 156388521         ok"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(3.1, 156388521, lambda: \n",
    "       execute(program))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "622d7010-145e-422a-a592-d4b446afcc0f",
   "metadata": {},
   "source": [
    "### Part 2: What do you get if you add up all of the results of just the enabled multiplications?\n",
    "\n",
    "For Part 2, the instruction \"`don't()`\"  says to **disable** (ignore) following multiply instructions until a \"`do()`\" instruction **enables** them again. I will define the function `enabled`, which returns the part of the program that is enabled, by susbstituting a space for the \"`don't()...do()`\" sequence (or a \"`don't()...`\" sequence that goes to the end of the file)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "4525d01a-bac0-41c2-92b8-baf0fd395e88",
   "metadata": {},
   "outputs": [],
   "source": [
    "def enabled_part(program: str) -> str:\n",
    "    \"\"\"Just the part of the program that is enabled; remove \"don't()...do()\" text.\"\"\"\n",
    "    return re.sub(r\"don't\\(\\).*?(do\\(\\)|$)\", \" \", program)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "ce40f258-ca76-48c3-9965-27a6979a4243",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  3.2:   .000 seconds, answer 75920122          ok"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(3.2, 75920122, lambda:\n",
    "       execute(enabled_part(program)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81b1ed3a-5bdb-4ef9-957d-25bcb19e3a00",
   "metadata": {},
   "source": [
    "### Part 3: Verification\n",
    "\n",
    "Regular expressions are [always tricky](https://blog.codinghorror.com/regular-expressions-now-you-have-two-problems/), so here are some assertions to give us more confidence that we got the components right (and to show some examples of their use)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "1cb1b8e5-1ad7-4364-8816-73669f9c0777",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assert all_multiplications(\"mul(1,2) + mul(34,5) - mul(67,89] / mul(x,15)\") == ['mul(1,2)', 'mul(34,5)']\n",
    "assert enabled_part(\"testing(1,2,3)\") == \"testing(1,2,3)\"\n",
    "assert enabled_part(\"preamble don't() middle part do() final\") == 'preamble   final'\n",
    "enabled_part(\"preamble don't() middle part no do, final\") == 'preamble  ' # Make sure it works without a closing \"do()\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e1448343-6488-45ad-b03d-d7928feb75cd",
   "metadata": {},
   "source": [
    "# [Day 4](https://adventofcode.com/2024/day/4): Ceres Search\n",
    "\n",
    "Today's puzzle is a 2D word-search puzzle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "a0d903b9-018e-4861-9314-cafed59055fd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 140 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "MASAMXMSSXXMAMXXMXMASXMASXMMSMSMMMAXMASASMMSSMSXAXMASMMSMMMSSMSASMSSSSMSMSMXXMXMAXAMXMSMSSXSAMXM ...\n",
      "MASMMXMASAXASMSMMMSAMXSMSAMXAAAAAXAMXASXAMAAAAMMSMMMMMASXAAAAMMAMAMMASAAAAXMXMSSSSSSMMSAMAXAXXSM ...\n",
      "MMXAXMMMSXMAMAAXAAXAAAXXSMMSMSMSMXAXMXSMMMMSSMXAMXAAXMAMMMMSSMMAMAMMAMMMMMXSAAXAAMMAXXSAMXMSMAXM ...\n",
      "SXSAMASASMSXMSMSMSSMMMMMMXAMXMMXMASMMMMAXXAAAMMMSSSSSMASXXAAXASMSXXMXSXSXSASMSMMSMSAMMMAMXAAMASX ...\n",
      "AAAXXXMASASXMXMAXXMMASAASMXSASASXAAAAMSSMMMSXMAAMMMMMXAXMMMMSAMXAMASAMXSAMASXXAXAAMAMXSAMXSXSMMA ...\n",
      "MSMMXXMMMAMAMMMMMMXSAXXAMMMMXSAXMMXXAMXAAMMXMASXMAAASMMXAAMXAXAMMMAMAMAMAMXMASXMMXMAAXMAXMAMXMSA ...\n",
      "MXAXAMXXMMMMSAMAASMMMSMMASASAMAMAXMSXMSMMXAMXAXMMSSXSASXSSSMAMSMXMXSAMSSSMAMXMXAMAXXMMSAXAXMMXMA ...\n",
      "ASXMMXSAMXAASXXMXSAAAXASAMMMASMSSSMAAMMXMMSSMASAMAMMMAMMAXMAXMASXMAXMSAAASASAMXSSMXSAAXSSMXAAXXA ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "xmas_grid = Grid(parse(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "16d56872-be2c-4e9d-8821-a0fe9f66970b",
   "metadata": {},
   "source": [
    "### Part 1: How many times does XMAS appear?\n",
    "\n",
    "We just have to find how many times the word \"XMAS\" appears in the grid, horizontally, vertically, or diagonally, forwards or backwards.  The variable `directions8` contains those eight directions (as (delta-x, delta-y) pairs). So examine each square of the grid and if it contains \"X\", see in how many of the directions it spells \"XMAS\". (Note that locations in the grid are denoted by `(x, y)` coordinates, as are directions (e.g., `(1, 0)` is the `East` direction. (The functions `add` and `mul` do addition and scalar multiplication on these 2D vectors.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "72d48abb-7a82-452f-b91d-838b3836a90f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def word_search(grid: Grid, word='XMAS') -> int:\n",
    "    \"\"\"How many times does the given word appear in the grid?\"\"\"\n",
    "    return quantify(grid_can_spell(grid, start, dir, word) \n",
    "                    for start in grid \n",
    "                    if grid[start] == word[0]\n",
    "                    for dir in directions8)\n",
    "\n",
    "def grid_can_spell(grid, start, dir, word):\n",
    "    \"\"\"Does `word` appear in grid starting at `start` and going in direction `dir`?\"\"\"\n",
    "    return all(grid[add(start, mul(dir, i))] == ch \n",
    "               for i, ch in enumerate(word))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "6175362b-d8b4-45d1-b70c-d8575a0fe188",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  4.1:   .021 seconds, answer 2401              ok"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(4.1, 2401, lambda:\n",
    "       word_search(xmas_grid))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eabe90c4-b668-4d9e-a345-b09f4b8ee42b",
   "metadata": {},
   "source": [
    "### Part 2: How many times does an X-MAS appear?\n",
    "\n",
    "Upon further review, the goal is not to find \"XMAS\" byt rather X-\"MAS\"; that is, two \"MAS\" words in an X pattern. The pattern can be any of these four:\n",
    "\n",
    "     M.S     S.M     M.M     S.S\n",
    "     .A.     .A.     .A.     .A.\n",
    "     M.S     S.M     S.S     M.M\n",
    "\n",
    "I decided to find these by first looking for each the middle letter (\"A\") in the grid, and then, for each \"A\" and for each of the four pairs of diagonal directions, see if the target word (\"MAS\") can be spelled in both directions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "3d8a051f-cf7b-4e8c-b0fb-78c3f089989d",
   "metadata": {},
   "outputs": [],
   "source": [
    "diagonal_pairs = ([SE, NE], [SW, NW],  [SE, SW], [NE, NW])\n",
    "\n",
    "def x_search(grid: Grid, word='MAS') -> int:\n",
    "    \"\"\"How many times does an X-MAS appear in the grid?\"\"\"\n",
    "    A_positions = grid.findall(word[1]) # All positions where an 'A' (the mid-letter 'MAS') appears\n",
    "    return quantify((grid_can_spell(grid, sub(mid_pos, dir1), dir1, word) and\n",
    "                     grid_can_spell(grid, sub(mid_pos, dir2), dir2, word))\n",
    "                    for mid_pos in A_positions\n",
    "                    for dir1, dir2 in diagonal_pairs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "64cde1d9-f58c-4633-b5da-87908a02f76d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  4.2:   .015 seconds, answer 1822              ok"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(4.2, 1822, lambda:\n",
    "       x_search(xmas_grid))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0249ce80-e649-44b3-8c02-613fc7652110",
   "metadata": {},
   "source": [
    "# [Day 5](https://adventofcode.com/2024/day/5): Print Queue\n",
    "\n",
    "Today's puzzle involves some **sleigh launch safety manuals** that need to be updated with new printings. The day's input is in two sections: the first a set of **rules** such as \"47|53\", which means that if an update prints both page 47 and page 53, then it must print 47 sometime before 53. The second section is a list of **updates** of the form \"75,47,61,53,29\", meaning that for one version of the safety manual, those are the pages that need to be printed, and that is the suggested order of printing.\n",
    "\n",
    "<img src=\"https://pbs.twimg.com/media/GeEU0XgWAAARMw-?format=jpg&name=medium\" width=400>\n",
    "\n",
    "I mostly like my `parse` function: it is easy to tell it how to break the input into sections and how to parse every section, if all the sections are the same. But I admit my `parse` is not ideal when an input file has sections with two different formats. I'll parse the two sections as paragraphs, and then call `parse` again on each paragraph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "b77a5a1f-a43b-4ce8-a60c-94d69a595505",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1366 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "48|39\n",
      "39|84\n",
      "39|23\n",
      "95|51\n",
      "95|76\n",
      "95|61\n",
      "14|52\n",
      "14|49\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 2 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "48|39\n",
      "39|84\n",
      "39|23\n",
      "95|51\n",
      "95|76\n",
      "95|61\n",
      "14|52\n",
      "14|49\n",
      "14|39\n",
      "14|53\n",
      "85|19\n",
      "85|25\n",
      "85|61\n",
      "85|35\n",
      "85|58\n",
      "74|86\n",
      " ...\n",
      "61,58,51,32,12,14,71\n",
      "58,25,54,14,12,94,32,76,39\n",
      "35,53,26,77,14,71,25,76,85,55,51,49,95\n",
      "32,91,76, ...\n"
     ]
    }
   ],
   "source": [
    "manual  = parse(5, sections=paragraphs)\n",
    "rules   = set(parse(manual[0], ints))\n",
    "updates = parse(manual[1], ints)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6e4d0b6-c69e-4284-9757-cf3ce51b196c",
   "metadata": {},
   "source": [
    "Here I show what the rules and updates look like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "4c85a23e-686a-4129-a14c-ff6f6a88b9ac",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert (48, 39) in rules # `rules` is a set of (earlier, later) page number pairs\n",
    "assert updates[0] == (61, 58, 51, 32, 12, 14, 71) # `updates` is a sequence of page number tuples"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6b6d374-cbe9-4b84-a1dd-d9df927c7182",
   "metadata": {},
   "source": [
    "### Part 1: What do you get if you add up the middle page number from the correctly-ordered updates?\n",
    "\n",
    "An update is correct if no combination of two pages in the update violates any of the rules. I'll define `is_correct` to implement this check, and `sum_of_correct_middles` to add up the middle numbers of the correct updates:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "78898d37-46ff-4367-9d89-b2a107a90aa1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def sum_of_correct_middles(rules: Set[Ints], updates: Tuple[Ints]) -> int:\n",
    "    \"\"\"The sum of the middle elements of each update that is correct.\"\"\"\n",
    "    return sum(middle(update) for update in updates if is_correct(update, rules))\n",
    "\n",
    "def is_correct(update: Ints, rules: Set[Ints]) -> bool:\n",
    "    \"\"\"An update is correct if no pair of pages violates a rule in the rules set.\"\"\"\n",
    "    return not any((second, first) in rules for (first, second) in combinations(update, 2))\n",
    "\n",
    "def middle(seq: Sequence) -> object: return seq[len(seq) // 2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "b1c87359-1d2d-4a90-8305-9d152ce5d547",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  5.1:   .001 seconds, answer 5762              ok"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(5.1, 5762, lambda:\n",
    "       sum_of_correct_middles(rules, updates))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80da4fd9-b11e-4dbb-8d22-2071d1a89827",
   "metadata": {},
   "source": [
    "### Part 2: What do you get if you add up the middle page numbers of the correction of each incorrect update?\n",
    "\n",
    "In Part 2 we have to find the incorrect updates, re-order them into a correct order, and sum the middle page numbers of just these corrected updates.\n",
    "Since I have already defined `is_correct`, I could just generate all permutations of each update and find one that `is_correct`. That would work great if the longest update consists of only 5 pages, as it does in the example input. But what is the longest update in *my* input?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "d8718c3e-0b3b-49ce-8cca-abd82aa788d7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "23"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "max(map(len, updates))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4449200f-dd19-48f1-94b2-7304daa9fa00",
   "metadata": {},
   "source": [
    "That's not great. With 23 page numbers there are 23! permutations, which is over 25 sextillion. So instead, here's my strategy:\n",
    "\n",
    "- Instead of generating all permutations, `correction` will **sort** an update, returning a corrected reordering that obeys all the rules. This is a [topological sort](https://en.wikipedia.org/wiki/Topological_sorting) and is guaranteed to give a correct reordering (unless the rules contain a contradiction like \"2 must be before 3 and 3 must be before 2\"). There may be multiple correct orderings (for example, if there are no rules involving the pages in the update, then any ordering is correct). It used to be that Python's `sort` method allowed a `cmp` keyword to compare two values; there is vestigial support for this with the `functools.cmp_to_key` function. I will sort each update so that page *m* comes before page *n* if (*m*, *n*) is in the rules, and *m* comes after *n* if (*n*, *m*) is in the rules. Sorting will be about a sextillion times faster than enumerating permutations.\n",
    "- `corrected` will find all the incorrect updates and correct them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "7222dc1c-067f-4bb5-84e1-3c2fc72fd53a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def correction(update: Ints, rules) -> Ints:\n",
    "    \"\"\"Reorder the update to make it correctly obey all the rules.\"\"\"\n",
    "    def rule_lookup(m, n): return +1 if (m, n) in rules else -1 if (n, m) in rules else 0\n",
    "    return sorted(update, key=functools.cmp_to_key(rule_lookup))\n",
    "\n",
    "def corrected(updates, rules) -> List[Ints]:\n",
    "    \"\"\"Returns a list of corrected versions of all the incorrect rules.\"\"\"\n",
    "    return [correction(update, rules) for update in updates if not is_correct(update, rules)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "494cda6e-6b07-4054-9b03-45f61bd4f973",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  5.2:   .001 seconds, answer 4130              ok"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(5.2, 4130, lambda:\n",
    "       sum_of_correct_middles([], corrected(updates, rules)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53b1ccbc-01ae-43d0-a75f-3f9389fdd3c9",
   "metadata": {},
   "source": [
    "I have to say, I'm pleased that so far I've had no bugs (other than simple typos like not closing a paren). Today I was worried I might have my `+1` and `-1` backwards in `cmp_to_key`, but so far, everything has gone smoothly. However,  I have no chance of showing up on the leaderboard;  I'm still *way* slower than skilled contest programmers, not to mention the automated large language models that some people are using."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38258423-e3b8-4bae-8aeb-28f07f0d5a35",
   "metadata": {},
   "source": [
    "# [Day 6](https://adventofcode.com/2024/day/6): Guard Gallivant\n",
    "\n",
    "Today's input is a 2D map of the manufacturing lab, with \"`.`\" indicating an empty space, \"`#`\" indicating an obstruction, and \"`^`\" indicating the position of the security guard, and the fact that the guard is initially facing North."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "6ec71cf8-c43d-457e-8e14-0e9eb99b956a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 130 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "........#........................................#......#........#.............................. ...\n",
      "....................................#......#.....#............#.............#..........#........ ...\n",
      "......................#.......................................................#................. ...\n",
      ".......#..#..#....#...#...#....#..............#......#.......#...#................#.......#..... ...\n",
      "......................#....##...#.......#....#.......................................#.......... ...\n",
      "...#............................#........................................#...................... ...\n",
      "....................#............#...............#......#.........#...........#................. ...\n",
      "............................#......#...#................#.............#......................... ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "lab_grid = Grid(parse(6))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ba233f4-90aa-4249-9569-10288c34940d",
   "metadata": {},
   "source": [
    "### Part 1: How many distinct positions will the guard visit before leaving the mapped area?\n",
    "\n",
    "The guard follows this protocol: \n",
    "- If there is something directly in front of you, turn right 90 degrees.\n",
    "- Otherwise, take a step forward.\n",
    "\n",
    "I'll define `follow_path` to return a list of all the positions the guard occupies. I realize the puzzle is only asking for a *count* of the positions, but the path might be useful for Part 2, or for debugging, so I'll return it. I worried that it is also possible for a path to become a loop, but the puzzle statement specifically says that can't happen (the guard will always march off the grid), so I won't test for it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "95f0b409-a6d6-47bc-8ce5-1c2df80f2b18",
   "metadata": {},
   "outputs": [],
   "source": [
    "def follow_path(grid: Grid, guard='^', facing=North) -> List[Point]:\n",
    "    \"\"\"A list of all points in the path followed by the guard.\n",
    "    The guard turns right when there is an obstacle ahead, otherwise goes forward.\"\"\"\n",
    "    path = grid.findall(guard) # A list of exactly one position, e.g. [(3, 4)]\n",
    "    while (ahead := add(path[-1], facing)) in grid:\n",
    "        if grid[ahead] == '#':\n",
    "            facing = make_turn(facing, 'R')\n",
    "        else:\n",
    "            path.append(ahead)\n",
    "    return path"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "f4be3d1f-7f24-4d55-8221-df0026178e1e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  6.1:   .001 seconds, answer 5329              ok"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(6.1, 5329, lambda: \n",
    "       len(set(follow_path(lab_grid))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eaf72ac3-ade0-4479-a090-1d0f292ecc27",
   "metadata": {},
   "source": [
    "I initially had a **bug**; I took the **length** of the path, not the \"distinct positions\", which I get by taking the length of the **set** of positions. For a  path that crosses itself these two numbers are different.\n",
    "                                  \n",
    "### Part 2: How many different positions could you choose for an obstruction to put the guard in a loop?\n",
    "\n",
    "The historians would like to place a single obstacle so that the guard *will* get stuck in a loop, rather than exiting the grid. They want to know all possible positions for the obstacle. What do we know about such positions?\n",
    "- An obstacle  position must be somewhere on the guard's path, otherwise it would have no effect.\n",
    "- The instructions say it can't be the guard's initial position.\n",
    "- A loop is when the guard's path returns to the same position with the same facing. This means my Part 1 solution, which returns the list of visited positions, without the facing directions, is not immediately helpful. \n",
    "- I can detect a loop by keeping a set of previously visited (position, facing) pairs.\n",
    "- I can save time and space by only storing the *corners* of the path: the places where the guard turns.\n",
    "    -  If the guiard is in a loop, the guard must turn the same way at the same corner.\n",
    "- The simplest approach for finding obstacle positions is to temporarily place an obstacle on each point on the path, one at a time, and see if it leads to a loop.\n",
    "- There are 5,329 positions on the path, so the runtime could be about 5,000 times longer than Part 1; on the order of 10 seconds or so.\n",
    "    - I'll try it, and if it seems too slow, I'll think of something else."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "1718fecb-aa3e-4162-9948-1c06d4ec5e8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_loopy_path(grid: Grid, guard_pos, facing=North) -> bool:\n",
    "    \"\"\"Does the path followed by the guard form a loop?\"\"\"\n",
    "    previous_positions = {(guard_pos, facing)}\n",
    "    while (ahead := add(guard_pos, facing)) in grid:\n",
    "        if grid[ahead] == '#':\n",
    "            facing = make_turn(facing, 'R')\n",
    "            if (guard_pos, facing) in previous_positions:\n",
    "                return True # Found a loop\n",
    "            previous_positions.add((guard_pos, facing))\n",
    "        else:\n",
    "            guard_pos = ahead\n",
    "    return False\n",
    "    \n",
    "def find_loopy_obstacles(grid: Grid) -> Iterable[Point]:\n",
    "    \"\"\"All positions in which placing an obstacle would result in a loopy path for the guard.\"\"\"\n",
    "    guard_pos = the(grid.findall('^'))\n",
    "    for pos in set(follow_path(grid)) - {guard_pos}:\n",
    "        grid[pos] = '#' # Temporarily place an obstacle \n",
    "        if is_loopy_path(grid, guard_pos):\n",
    "            yield pos\n",
    "        grid[pos] = '.' # Remove the temporarily-placed obstacle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "36196264-eb33-4fc0-95d5-06c985105ebf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  6.2:  1.932 seconds, answer 2162              ok"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(6.2, 2162, lambda:\n",
    "       quantify(find_loopy_obstacles(lab_grid)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9f3ee6f9-7ec7-4248-ae52-1804fdc81dbd",
   "metadata": {},
   "source": [
    "That was my first run time over a second, but still faster than I thought it would be. I guess many of the obstacles force the guard into a small, fast loop, or an early exit from the grid. Note that in `the(grid.findall('^'))`, `findall` is a method from my `Grid` class that finds all locations where a `'^'` character resides, and `the` is my utility function that returns the first element of a one-element list (and raises an error if there is not exactly one element).\n",
    "\n",
    "I had a **bug** initially, and never figured out what it was; it went away when I refactored to make the program nicer."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9eae8cf2-8c97-418e-b00b-3ea0187da526",
   "metadata": {},
   "source": [
    "# [Day 7](https://adventofcode.com/2024/day/7): Bridge Repair\n",
    "\n",
    "The narrative for today involves fixing a bridge, and each line of our input represents a **calibration equation** for the bridge. Unfortunately, some nearby elephants stole all the operators from the equations, so all that is left are the integers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "c1c6cee8-122c-43c9-8c7d-ed8980ea2b76",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 850 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "202998336: 686 9 7 62 2 673\n",
      "19275222: 361 3 7 170 65 5 223\n",
      "23101: 7 694 916 4 6\n",
      "2042426: 6 34 2 423 3\n",
      "40369523: 8 880 91 45 23\n",
      "46629044796: 990 471 4 4 796\n",
      "1839056: 3 42 2 4 3 258 703 4 8\n",
      "26205: 2 9 5 9 9 4 3 7 44 5 8 7\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 850 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(202998336, 686, 9, 7, 62, 2, 673)\n",
      "(19275222, 361, 3, 7, 170, 65, 5, 223)\n",
      "(23101, 7, 694, 916, 4, 6)\n",
      "(2042426, 6, 34, 2, 423, 3)\n",
      "(40369523, 8, 880, 91, 45, 23)\n",
      "(46629044796, 990, 471, 4, 4, 796)\n",
      "(1839056, 3, 42, 2, 4, 3, 258, 703, 4, 8)\n",
      "(26205, 2, 9, 5, 9, 9, 4, 3, 7, 44, 5, 8, 7)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "equations = parse(7, ints)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be207b67-a970-4f79-85be-5d62b7cedd9f",
   "metadata": {},
   "source": [
    "<img src=\"https://pbs.twimg.com/media/GeOKVYiX0AAwNMy?format=jpg&name=medium\" width=400> "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e31d28f-97b1-4a3d-a298-18fcad297150",
   "metadata": {},
   "source": [
    "### Part 1: What is the total calibration result of possibly true equations?\n",
    "\n",
    "Our task is to find operators to balance each equation. The input \"`3267: 81 40 27`\" can be made into the equation \"`3267 = 81 + 40 * 27`\", with the understanding that all evaluations are done left-to-right, so this is \"`3267 = ((81 + 40) * 27)`\". The two allowable operators are addition and multiplication. Our task is to compute the sum of all the equations that can be balanced.\n",
    "\n",
    "The straightforward approach is to try both operators on every number. If there are *n* numbers in an equation, then there are *n* - 1 numbers on the right-hand side, and *n* - 2 missing operators, so there will be 2<sup>*n*-2</sup> possible equations. Is that going to be a problem?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "6fa3907c-0e1a-4d4a-9fc3-f809b9325674",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "13"
      ]
     },
     "execution_count": 69,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "max(map(len, equations))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0d9b0b2-fe1e-434e-b84e-c044da3d3673",
   "metadata": {},
   "source": [
    "No problem! With 13 numbers on a line there are just 2<sup>11</sup> = 2048 equations; a small number.  I'll define `can_be_calibrated` to try all possible operator combinations. It goes left-to-right, one number at a time, keeping a list of partial `results` which is updated for each new number in the equation. \n",
    "\n",
    "Although the puzzle instructions are a bit vague, it appears that when they say \"numbers\" they mean \"positive integers\". Therefore, neither addition nor multiplication can cause a partal result to decrease, so once a partial result exceeds the target, we can drop it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "5dfe0edf-cf29-4623-bb2c-6180f832f4d7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def can_be_calibrated(equation: ints, operators=(operator.add, operator.mul)) -> bool:\n",
    "    \"\"\"Can the equation be balanced using '+' and '*' operators?\"\"\"\n",
    "    target, first, *rest = equation\n",
    "    results = [first] # A list of all possible results of the partial computation\n",
    "    for y in rest:\n",
    "        results = [op(x, y) for x in results if x <= target for op in operators]\n",
    "    return target in results\n",
    "\n",
    "def lhs(equation) -> int: \"Left-hand side\"; return equation[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "3085596d-f5ec-4ba8-b05a-cf70cf276a0c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  7.1:   .014 seconds, answer 1985268524462     ok"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(7.1, 1985268524462, lambda:\n",
    "    sum(lhs(equation) for equation in equations if can_be_calibrated(equation)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62a5fe5f-e23f-4420-87a8-47d8be02fbc0",
   "metadata": {},
   "source": [
    "### Part 2: What is the total calibration result of possibly true equations, allowing concatenation?\n",
    "\n",
    "In Part 2, a third operator is allowed: **concatentation**. The equation \"`192: 17 8 14`\" can be balanced by concatenated 17 and 8 to get 178, and then adding 14 to get 192: \"`192 = ((17 || 8) + 14)`\". With three possible operators, the equation with 11 missing operator slots now has 3<sup>11</sup> = 177,147 possibilities, almost 100 times more than Part 1, so this will take longer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "393a50cf-f136-446a-a97e-c501669ce89f",
   "metadata": {},
   "outputs": [],
   "source": [
    "operators3 = (operator.add, operator.mul, lambda x, y: int(str(x) + str(y)))    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "f8e75ea3-e8ba-4b33-8efe-8bf74357e35d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  7.2:   .776 seconds, answer 150077710195188   ok"
      ]
     },
     "execution_count": 75,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(7.2, 150077710195188, lambda:\n",
    "       sum(lhs(equation) for equation in equations if can_be_calibrated(equation, operators3)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "128b4857-ed3e-49f5-97f5-9d9afd46408d",
   "metadata": {},
   "source": [
    "That was easy, but it is the second-slowest runtime so far. I can make it faster by implementing concatenation by multiplying and adding rather than by string operations."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "6fe6adad-a3a6-49b8-b49e-6098b27e3a44",
   "metadata": {},
   "outputs": [],
   "source": [
    "operators3 = (operator.add, operator.mul, lambda x, y: (x * 10 ** num_digits(y)) + y)\n",
    "\n",
    "def num_digits(n: int) -> int:\n",
    "    \"\"\"The number of digits in a positive integer.\"\"\"\n",
    "    if n < 10:     return 1 ## Three special cases cover most calls\n",
    "    elif n < 100:  return 2\n",
    "    elif n < 1000: return 3\n",
    "    result = 1\n",
    "    while n >= 10:\n",
    "        result += 1\n",
    "        n /= 10\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "id": "ffb673f1-af9d-4d15-8f8d-92e29489dd78",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  7.2:   .586 seconds, answer 150077710195188   ok"
      ]
     },
     "execution_count": 78,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(7.2, 150077710195188, lambda:\n",
    "       sum(numbers[0] for numbers in equations if can_be_calibrated(numbers, operators3)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2e5693b7-dab8-4f89-a000-c69ee75a11c9",
   "metadata": {},
   "source": [
    "# [Day 8](https://adventofcode.com/2024/day/8): Resonant Collinearity\n",
    "\n",
    "Another grid input, this one a map of antenna locations. Each different non-\"`.`\" character denotes an antenna of a given frequency."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "cf6361a7-e3bc-42ec-ae16-f9eec166055e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 50 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "..................................................\n",
      ".................................C................\n",
      ".e..........7O....................................\n",
      ".....................................z............\n",
      "......................t.........C.......k.........\n",
      "............h................................9....\n",
      ".............5.7....O.............9C..............\n",
      ".......5.O................T.......................\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "antennas = Grid(parse(8))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c8e1006d-37bc-432e-bf1f-7a639287382a",
   "metadata": {},
   "source": [
    "### Part 1: How many unique locations within the bounds of the map contain an antinode?\n",
    "\n",
    "An **antinode** is defined as a point that is perfectly in line with two antennas of the same frequency, but only when one of the antennas is twice as far away as the other.\n",
    "\n",
    "That means that if two antennas are at points *A* and *B*, then the two antinodal points are at 2*A* - *B* and 2*B* - A. If there are three or more antennas with the same frequency then we consider each pair of them in turn. So all we have to do is group the antennas by frequency, compute the antinodes for each pair with the same frequency, and determine which of those antinodal points are on the grid."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "22180ce8-5d03-4aee-8c73-62f2afbddf71",
   "metadata": {},
   "outputs": [],
   "source": [
    "def antinodes(antennas: Grid) -> Set[Point]:\n",
    "    \"\"\"The set of all antinodal points for all antennas in the grid.\n",
    "    (That is, points that are of distance d and 2d from same frequency antennas.)\"\"\"\n",
    "    groups = [antennas.findall(f) for f in set(antennas.values()) if f != '.']\n",
    "    return union(antinodes2(A, B, antennas)\n",
    "                 for points in groups\n",
    "                 for A, B in combinations(points, 2))\n",
    "\n",
    "def antinodes2(A: Point, B: Point, antennas: Grid) -> Set[Point]:\n",
    "    \"\"\"The set of antinodal points for two antenna points, A and B.\"\"\"\n",
    "    candidates = [sub(mul(A, 2), B), sub(mul(B, 2), A)]\n",
    "    return {P for P in candidates if P in antennas}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "dd173ce9-cbbb-4282-b43f-c7cff662bd90",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  8.1:   .002 seconds, answer 220               ok"
      ]
     },
     "execution_count": 83,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(8.1, 220, lambda:\n",
    "       len(antinodes(antennas)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff79d605-813a-46ac-8473-a1198be0e99f",
   "metadata": {},
   "source": [
    "### Part 2: How many unique locations within the bounds of the map contain an resonant antinode?\n",
    "\n",
    "For Part 2, a Historian tells us to consider **resonant antinodes**, which  can occur at *any* point that is exactly on line with two antennas of the same frequency, regardless of distance. So if the two antennas are *A* and *B* then the antinodal points can be found by starting at *A* and going step by step in the direction of the vector *A* - *B* and also in the direction *B* - *A*, going as far as you can while staying on the grid. The `Grid.follow_line` method facilitates that.\n",
    "\n",
    "I'll refactor `antinodes` to take an `antinodes2` parameter so it can handle both parts:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "d30f8ce9-f186-46a0-a2e7-f74eceae6905",
   "metadata": {},
   "outputs": [],
   "source": [
    "def antinodes(antennas: Grid, antinodes2=antinodes2) -> Set[Point]:\n",
    "    \"\"\"The set of all antinodal points in the grid, according to the `antinode2` function.\"\"\"\n",
    "    groups = [antennas.findall(f) for f in set(antennas.values()) if f != '.']\n",
    "    return union(antinodes2(A, B, antennas)\n",
    "                 for points in groups\n",
    "                 for A, B in combinations(points, 2))\n",
    "\n",
    "def resonant_antinodes2(A: Point, B: Point, antennas: Grid) -> Set[Point]:\n",
    "    \"\"\"The set of resonant antinodal points for two antenna points, A and B.\"\"\"\n",
    "    return (set(antennas.follow_line(A, sub(A, B))) | \n",
    "            set(antennas.follow_line(A, sub(B, A))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "6bf85b57-8b8f-4196-9903-6d5fe082f404",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  8.1:   .002 seconds, answer 220               ok"
      ]
     },
     "execution_count": 86,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(8.1, 220, lambda:\n",
    "       len(antinodes(antennas)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "f232952c-5fc6-4696-a8b1-d0b54137ac02",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  8.2:   .003 seconds, answer 813               ok"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(8.2, 813, lambda:\n",
    "       len(antinodes(antennas, resonant_antinodes2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ff92b7f-f9e9-4664-9fc5-0e9998aca47e",
   "metadata": {},
   "source": [
    "### Part 3: Visualization\n",
    "\n",
    "Here I show what the grid look like with all the resonant antinodes depicted with the same letter as their antenna."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "4642cbba-16c1-4aa8-b39d-a104a475cbe6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "..........E7...xH..s....B.C........z..W..........5\n",
      ".........4O.5..H3...t..h....3.s..C.3..zo..35b.....\n",
      ".e.....x..x.7OH.x....t..8....CT...z.o5............\n",
      "5...........XH...s...t.....s...5j...8z.T.3........\n",
      "...........EH...ex.Tj3t.E5....3.C....E..k.O....c.w\n",
      ".30........Hh...Kb.5.t.cs......O.S..z..k3....9..Eo\n",
      ".......3..H..5.s..x.O..B..........9C3..zcb....o.wX\n",
      ".......5.O.x.3.......st9..3...8C3j..W..3...o.G....\n",
      ".5.0....H...E......x.........o...c....C.o......w..\n",
      ".9H....H.c...sex.7s...tj.3.....b...E.o3..K.....w..\n",
      "......H..........67.x.....cO..C3.T3.5..8.C..E.w..S\n",
      "sW..0H....H...5s.........B6....o..j..Cb.z..c......\n",
      ".s..6O.....s.EHx...c.xBt....o.......8.....e3Cw..S.\n",
      "..sH.k..O...s.....H..H.E.o.e.C......3..zT.......X3\n",
      "T.Hs.0.....ke.......H7x..4j..H...EO..9..K.z.w..C..\n",
      ".H..s....T.H.....k.o.5..H.H........3.H..E.G..0....\n",
      "H....c.......1E5o.T.x.7x...eC.j.4..b..3C.3.0.HST..\n",
      ".O....s......oH....x....t..T.k....3S....e08.z.....\n",
      ".......s..o..........B.7x.........HHT.H0zOw..S....\n",
      "...s...os.e......H.......b.C5j.E.3C.j0.K3kHz.T31.J\n",
      "..g.o..0.s.....E........tx.........0E....H..S.HX..\n",
      "so...s....s.....5...H....t....K.30w....3.Cz...H.J.\n",
      "....KS...o.s..........Ex.tx7X..0........9K3S.3..8.\n",
      "........0...s6.........Hkx.7.9.3...5Sj.wez.....Jz.\n",
      ".4.O....e....s..E...BT....wx1E..j.....Kw..S.z8....\n",
      ".E....O.....K.s..........Ct...38E.j......W..3.J...\n",
      "....h...o0.g...s.8.....e.w..xb7.......wT3S8C.....j\n",
      "02.8........S...s.wW.0....txT3.......wj...5.cJX..Z\n",
      "..J...k.......84.E.0K...Ct...xW......w.8S.z...3..G\n",
      "...0E.e...0......0sk.......E3...H..j.K......JzT...\n",
      "..........w....0.gkB.....kttE.x777.w8..S...9..GG..\n",
      ".....O0......0.Tw.5.sE.C..b3K......HG..j.3.JzC..35\n",
      "S2..2......0......ESg9.....t...x.C.w..S....1G..z..\n",
      "B.w4...E.0..........8ws...3.t...1b....H...Jz...X..\n",
      "....e.B0.....h.......1Cs.E....8.x.w.CSjWG.T..XZ...\n",
      "6....0..S.1.B.k.........E3..W.........S.jH.......z\n",
      "...0...w.6.......WBE...b.st8....wx.7SG....3..z.C..\n",
      ".0..O.W2..E....0..6..C..3.s.tt.w...x.7..J...H.....\n",
      ".........T...0..S.......8..6tgB.w.xS...7....z.9...\n",
      "..e...............0....E....st...G.K67.J.j....EH..\n",
      "...2W...............E8.......s.wg.Sx.b...EB..6....\n",
      "........28..jE0W....b03.S.....t.....E.JS...3X.z.BC\n",
      ".....4..k.2..2...B8...h...WjGtwE.S.gx..x..7..T...z\n",
      "..oO...k..........2C.3..0.ESt...s....J....j..zg...\n",
      "e.....G........8.....E.2.G.t.w..SsK..xg.x.7Jj...W.\n",
      "...T....w....jGSE...3......02..6C.b.J..1.7.......X\n",
      ".........S.E8....bC..5G.....w..K.2.s..x..G..37.X.9\n",
      "...Sk.E...B..2..0..2.....S....t....Js.2.Sb.x.X....\n",
      ".E.......8......B..G..E....w..St.....sGxZ..2g.z...\n",
      "4.O..6..G........C3E....W....2..t0J.g.C..X....Gj2.\n"
     ]
    }
   ],
   "source": [
    "def show_antinodes(antennas: Grid, antinodes2=resonant_antinodes2):\n",
    "    \"\"\"Put antinodes on the grid and print.\"\"\"\n",
    "    antennas = antennas.copy() # Don't alter the original\n",
    "    groups = {f: antennas.findall(f) for f in set(antennas.values()) if f != '.'}\n",
    "    for f, points in groups.items():\n",
    "        for A, B in combinations(points, 2):\n",
    "            for p in antinodes2(A, B, antennas):\n",
    "                antennas[p] = f\n",
    "    antennas.print()\n",
    "                 \n",
    "show_antinodes(antennas.copy())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4835cad-7777-4636-b9af-52cc9782b2b8",
   "metadata": {},
   "source": [
    "# [Day 9](https://adventofcode.com/2024/day/9): Disk Fragmenter\n",
    "\n",
    "Today we're confronted with a computer disk that needs to be compressed to gain some contiguous free space. The contents of the disk is represented in the **disk map** format: a string of digits, where the digits alternate between the number of blocks of a file, followed by the number of blocks of free space. We'll parse that as a tuple of digits:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "id": "0e944f9e-5c16-440c-b12e-178058a87048",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1 str:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "692094513253604282899448234539616972499153261626907217394161512944107098953354935354419233821564 ...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 1 tuple:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(6, 9, 2, 0, 9, 4, 5, 1, 3, 2, 5, 3, 6, 0, 4, 2, 8, 2, 8, 9, 9, 4, 4, 8, 2, 3, 4, 5, 3, 9, 6, 1, ...\n"
     ]
    }
   ],
   "source": [
    "disk_map = the(parse(9, digits))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99d40379-65e1-4872-8c68-17ba4925c24e",
   "metadata": {},
   "source": [
    "<img src=\"https://pbs.twimg.com/media/GeYt7iuWIAAHxhT?format=jpg&name=medium\" width=400>\n",
    "\n",
    "### Part 1: Compress the hard drive. What is the resulting filesystem checksum? \n",
    "\n",
    "We will deal with two formats to represent disks. Consider this **disk map** format:\n",
    "\n",
    "     1, 2, 3, 4, 5  ## Disk map format\n",
    "\n",
    "This means that there is 1 block for the first file (which has ID number 0), followed by 2 empty blocks, then 3 blocks for the second file (with ID number 1), followed by 4 empty blocks, and finally 5 blocks for the third file (with ID number 2).  \n",
    "\n",
    "It makes sense to convert this into a **disk layout** format:  which would be \"`\", where \"`.`\" represents an empty block.\n",
    "\n",
    "     0..111....22222  ## Disk layout format\n",
    "\n",
    "Here the integers represent file ID numbers, and the `.` indicates an empty block.\n",
    "\n",
    "To **compress** a disk layout, move file blocks one at a time starting by taking the rightmost non-empty block and moving it to the leftmost empty position; repeat until no more moves are possible.  For the example above, that would give us:\n",
    "\n",
    "     022111222......  ## Disk layout format (compressed)\n",
    "\n",
    "The final answer to the puzzle is a **checksum** of the compressed disk: the sum of the product of the block position times the file ID number for all non-empty blocks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "id": "76e8454d-a2f3-4b6b-92df-182116cf46e0",
   "metadata": {},
   "outputs": [],
   "source": [
    "empty = -1 # An empty block\n",
    "\n",
    "def disk_layout(disk_map: Ints) -> list:\n",
    "    \"\"\"Convert a disk map into a disk layout.\"\"\"\n",
    "    def empties(j) -> int: return (disk_map[j] if j < len(disk_map) else 0)\n",
    "    return append(disk_map[i] * [id] + empties(i + 1) * [empty]\n",
    "                  for id, i in enumerate(range(0, len(disk_map), 2)))\n",
    "\n",
    "def compress_layout(layout: list) -> list:\n",
    "    \"\"\"Mutate layout by moving blocks one at a time from the end to the leftmost free space.\"\"\"\n",
    "    N    = len(layout)\n",
    "    free = -1  # Start looking for free space from the left\n",
    "    end  = N   # Start looking for non-empty blocks from the right\n",
    "    while True:\n",
    "        free = first(i for i in range(free + 1, N)    if layout[i] is empty)\n",
    "        end  = first(i for i in range(end - 1, 0, -1) if layout[i] is not empty)\n",
    "        if free is None or free >= end:\n",
    "            return layout\n",
    "        layout[free], layout[end] = layout[end], empty\n",
    "\n",
    "def checksum(layout: list) -> list:\n",
    "    \"\"\"The sum of the product of the block position times the file ID number for all non-empty blocks.\"\"\"\n",
    "    return sum(i * id for i, id in enumerate(layout) if id is not empty)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "id": "2aa7e2b9-844e-49ed-b41b-4a4cecff86b7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  9.1:   .019 seconds, answer 6332189866718     ok"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(9.1, 6332189866718, lambda:\n",
    "       checksum(compress_layout(disk_layout(disk_map))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c05a497-cc66-4698-b88b-25c33eea224a",
   "metadata": {},
   "source": [
    "### Part 2: Compress the hard drive with the new method. What is the resulting filesystem checksum? \n",
    "\n",
    "In Part 2, there is a new method of compressing the disk, where we move full files rather than a block at a time. Again we start on the right, and try to move a file to the leftmost position where it will fit. If there is no such position, the file doesn't move. `compress_layout2`  implements this new method, performing a move by swapping two [**slices**](https://docs.python.org/3/library/functions.html#slice) of the disk layout: \n",
    "\n",
    "    layout[file], layout[free] = layout[free], layout[file]`\n",
    "\n",
    "To find all the slices that indicate files, it is easier to run through the disk map than the disk layout. The function `file_slices` quickly finds all such slices.\n",
    "\n",
    "Finding a free space for a file is more difficult than finding a single free block, because we need to find free space that is big enough. At first I coded a solution that ran through the whole layout from left-to-right each time, looking for the first sufficiently-large free space. That made it *O*(*n*<sup>2</sup>), but it should be *O*(*n*) So I added a table: `starts[length]` that tells me where to start looking for an empty space of size `length`, and updated the table every time I move a file. That speeds things up by a factor of 100."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "id": "8d34e96a-8ea9-4f92-b0aa-839b216ea14b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def compress_layout2(disk_map: Ints) -> list:\n",
    "    \"\"\"Mutate layout by moving files one at a time from the end to the leftmost free space.\"\"\"\n",
    "    layout = disk_layout(disk_map)\n",
    "    starts = defaultdict(int)\n",
    "    for file in file_slices(disk_map):\n",
    "        if free := find_freespace(layout, file, starts):\n",
    "            layout[file], layout[free] = layout[free], layout[file]\n",
    "    return layout\n",
    "\n",
    "def file_slices(disk_map: Ints) -> List[slice]:\n",
    "    \"\"\"Given a disk map, find all the slice positions of files in the disk layout (last one first).\"\"\"\n",
    "    slices = []\n",
    "    block = 0\n",
    "    for i, length in enumerate(disk_map):\n",
    "        if i % 2 == 0:\n",
    "            slices.append(slice(block, block + length))\n",
    "        block += length\n",
    "    slices.reverse()\n",
    "    return slices\n",
    "\n",
    "def find_freespace(layout, file_slice, starts) -> Optional[slice]:\n",
    "    \"\"\"Find a slice position big enough to fit the given file slice, or return None if there is no position.\"\"\"\n",
    "    length = file_slice.stop - file_slice.start\n",
    "    run = 0 # The number of consecutive empty spaces we have found so far\n",
    "    for i in range(layout.index(empty, starts[length]), len(layout)):\n",
    "        starts[length] = i\n",
    "        if i >= file_slice.start:\n",
    "            return None # We only want to move a file left, not right\n",
    "        elif layout[i] is empty: # Look for empty spaces one by one\n",
    "            run += 1\n",
    "            if run == length:\n",
    "                return slice(i + 1 - length, i + 1)\n",
    "        else:\n",
    "            run = 0\n",
    "    return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "id": "e3036875-88d0-496e-9d2f-facd0e80a5b2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle  9.2:   .021 seconds, answer 6353648390778     ok"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(9.2, 6353648390778, lambda:\n",
    "       checksum(compress_layout2(disk_map)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24c0e7d7-6ac7-4e4b-9557-bd4e215ad0a9",
   "metadata": {},
   "source": [
    "I got the right answer, but I confess I had an off-by-one **bug** in `find_freespace` on the first try, and another bug where I didn't check if `if i >= file_slice.start`, and was sometimes moving a large file to the right (thereby *uncompressing* the disk) rather than leaving it in place."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a900425-fe22-4d2f-8d1d-46c319c109e9",
   "metadata": {},
   "source": [
    "# [Day 10](https://adventofcode.com/2024/day/10): Hoof It\n",
    "\n",
    "Today's input is a topological map of hiking paths on Lava Island, with digits indicating the elevation of each terrain position."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "id": "5804fb03-05f3-402f-b6cc-6804c5d22512",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 60 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "432109865210212123765432101234321098543289654320132112121058\n",
      "045678774324301012892343023445456787650198763013241001034569\n",
      "187678789465692321001056014896234986456787012894653212123678\n",
      "296589921056789433217837895687145675323891233765784589238987\n",
      "345437835434576544786921278761010014210710321212098676521067\n",
      "032126546323465435695430789760121223121653450303145125430678\n",
      "123010567810156543212345699859834321056544067654236012321589\n",
      "543213498987657665401030787348765430187432198765987622345432\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 60 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(4, 3, 2, 1, 0, 9, 8, 6, 5, 2, 1, 0, 2, 1, 2, 1, 2, 3, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, ...\n",
      "(0, 4, 5, 6, 7, 8, 7, 7, 4, 3, 2, 4, 3, 0, 1, 0, 1, 2, 8, 9, 2, 3, 4, 3, 0, 2, 3, 4, 4, 5, 4, 5, ...\n",
      "(1, 8, 7, 6, 7, 8, 7, 8, 9, 4, 6, 5, 6, 9, 2, 3, 2, 1, 0, 0, 1, 0, 5, 6, 0, 1, 4, 8, 9, 6, 2, 3, ...\n",
      "(2, 9, 6, 5, 8, 9, 9, 2, 1, 0, 5, 6, 7, 8, 9, 4, 3, 3, 2, 1, 7, 8, 3, 7, 8, 9, 5, 6, 8, 7, 1, 4, ...\n",
      "(3, 4, 5, 4, 3, 7, 8, 3, 5, 4, 3, 4, 5, 7, 6, 5, 4, 4, 7, 8, 6, 9, 2, 1, 2, 7, 8, 7, 6, 1, 0, 1, ...\n",
      "(0, 3, 2, 1, 2, 6, 5, 4, 6, 3, 2, 3, 4, 6, 5, 4, 3, 5, 6, 9, 5, 4, 3, 0, 7, 8, 9, 7, 6, 0, 1, 2, ...\n",
      "(1, 2, 3, 0, 1, 0, 5, 6, 7, 8, 1, 0, 1, 5, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 9, 9, 8, 5, 9, 8, 3, ...\n",
      "(5, 4, 3, 2, 1, 3, 4, 9, 8, 9, 8, 7, 6, 5, 7, 6, 6, 5, 4, 0, 1, 0, 3, 0, 7, 8, 7, 3, 4, 8, 7, 6, ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "topo = Grid(parse(10, digits))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d951807a-3611-445f-84ee-352221a25968",
   "metadata": {},
   "source": [
    "### Part 1: What is the sum of the scores of all trailheads on your topographic map?\n",
    "\n",
    "A **trailhead** is any position with elevation  0, and a **peak** is any position with elevation 9. The **score** of a trailhead is the number of peaks that can be reached by following a path where each step increases the elevation by exactly 1. All steps are in one of the four cardinal directions (north/south/east/west).\n",
    "\n",
    "I'll keep a set of points on the frontier of possible paths, updating this set on each iteratation from 1 to 9, by looking at each point on the frontier and seeing which of the neighboring points `p` have the right elevation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "id": "76b5379e-ee19-4607-91b8-88ec7b38023f",
   "metadata": {},
   "outputs": [],
   "source": [
    "def score(topo: Grid, trailhead: Point) -> int:\n",
    "    \"\"\"How many peaks can be reached from this trailhead?\"\"\"\n",
    "    frontier = {trailhead}\n",
    "    for elevation in range(1, 10):\n",
    "        frontier = {p for p in union(map(topo.neighbors, frontier))\n",
    "                    if topo[p] == elevation}\n",
    "    return len(frontier)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "id": "97cf05f7-fa56-4a90-b2d8-2cd4d9b81f95",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 10.1:   .005 seconds, answer 744               ok"
      ]
     },
     "execution_count": 103,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(10.1, 744, lambda:\n",
    "       sum(score(topo, trailhead) for trailhead in topo.findall([0])))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4656eb08-b12a-4a02-92b8-ac23f2361387",
   "metadata": {},
   "source": [
    "### Part 2: What is the sum of the ratings of all trailheads?\n",
    "\n",
    "The **rating** of a trailhead is the number of distinct paths from the trailhead to a peak.\n",
    "\n",
    "As in Part 1, I'll keep a frontier and update it on each iteration from 1 to 9, but this time the frontier will be a counter of `{position: count}` where the count indicates the number of paths to that position. On each iteration I'll look at each point `f` on the frontier and see which of the neighboring points `p` have the right elevation, and increment the counts for those points by the count for `f`. This approach is linear in the number of positions, whereas if I followed all possible paths depth-first there could be an exponential number of paths."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "id": "b763450f-a565-4936-bee4-e531c2eeebdb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def rating(topo: Grid, trailhead: Point) -> int:\n",
    "    \"\"\"How many distinct paths are there from this trailhead to any peak?\"\"\"\n",
    "    frontier = Counter({trailhead: 1})\n",
    "    for elevation in range(1, 10):\n",
    "        frontier = accumulate((p, frontier[f]) \n",
    "                              for f in frontier\n",
    "                              for p in topo.neighbors(f) \n",
    "                              if topo[p] == elevation)\n",
    "    return sum(frontier.values())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfb4ae54-db59-44df-a76d-12e155fd1e5e",
   "metadata": {},
   "source": [
    "(Note my [utility function](AdventUtils.ipynb) `accumulate` takes as input an iterable of (key, count) pairs, and returns a Counter of the total count for each key.)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "f8a87032-6556-4fc9-9bb8-573611aee8dc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 10.2:   .006 seconds, answer 1651              ok"
      ]
     },
     "execution_count": 107,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(10.2, 1651, lambda:\n",
    "       sum(rating(topo, trailhead) for trailhead in topo.findall([0])))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af410d30-7096-4be6-bb20-904b3c8e2f59",
   "metadata": {},
   "source": [
    "### Part 3: Visualization\n",
    "\n",
    "Here's a visualization of the map:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "id": "eea7e277-4687-48a9-85b5-a031a9d4b6e1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_topo(topo: Grid):\n",
    "    \"\"\"Show the map with a colormap from blue to red.\"\"\"\n",
    "    scatter = plt.scatter(Xs(topo), Ys(topo), c=list(topo.values()), \n",
    "                          cmap='coolwarm', marker='s', s=12)\n",
    "    plt.colorbar(scatter, label='Elevation')\n",
    "    plt.axis('square')\n",
    "    plt.axis('off')\n",
    "    plt.show()\n",
    "\n",
    "plot_topo(topo)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e01d7f5-d0f0-4e7b-8cab-eef2afc02f6b",
   "metadata": {},
   "source": [
    "# [Day 11](https://adventofcode.com/2024/day/11): Plutonian Pebbles\n",
    "\n",
    "Today's narrative involves a straight line of stones, each of which has a number enscribed on it. The input is a single line of these numbers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "id": "76b68cef-d8de-4145-b65c-b254fedf1671",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1 str:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "0 27 5409930 828979 4471 3 68524 170\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 1 tuple:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(0, 27, 5409930, 828979, 4471, 3, 68524, 170)\n"
     ]
    }
   ],
   "source": [
    "stones = the(parse(11, ints))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "a7302dc5-5163-4f0b-bdcc-8c00e367391c",
   "metadata": {},
   "source": [
    "### Part 1: How many stones will you have after blinking 25 times?\n",
    "\n",
    "Every time you **blink**, the stones appear to change, according to these rules:\n",
    "- A stone marked 0 changes to 1.\n",
    "- Otherwise, a stone with an even number of digits splits into two stones, with the first and second halves of those digits.\n",
    "- Otherwise, the stone's number is multiplied by 2024.\n",
    "\n",
    "<img src=\"https://pbs.twimg.com/media/GejUQBgWIAAUtDf?format=jpg&name=medium\" width=400>\n",
    "\n",
    "\n",
    "I'll define `blink` to simulate the effect of a given number of blinks, and `change_stone` to change a single stone, returning a list of either one or two stones (the two stones computed by `split_stone`):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "id": "1513df56-3d6f-42cf-8aec-1bdbeb991d90",
   "metadata": {},
   "outputs": [],
   "source": [
    "def blink(stones: Ints, blinks=25) -> List[int]:\n",
    "    \"\"\"Simulate the changes in the list of stones after blinking `blinks` times.\"\"\"\n",
    "    for _ in range(blinks):\n",
    "        stones = append(map(change_stone, stones))\n",
    "    return stones\n",
    "    \n",
    "def change_stone(stone: int) -> List[int]:\n",
    "    \"\"\"Change a single stone into one or two, according to the rules.\"\"\"\n",
    "    digits = str(stone)\n",
    "    return ([1]                 if stone == 0           else\n",
    "            split_stone(digits) if len(digits) % 2 == 0 else\n",
    "            [stone * 2024])\n",
    "\n",
    "def split_stone(digits: str) -> List[int]:\n",
    "    \"\"\"Split a stone into two halves.\"\"\"\n",
    "    half = len(digits) // 2\n",
    "    return [int(digits[:half]), int(digits[half:])]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "id": "eff17cd0-a2c7-4d69-bc55-c0ef97917915",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 11.1:   .066 seconds, answer 194482            ok"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(11.1, 194482, lambda:\n",
    "       len(blink(stones, 25)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f65e94f-43e8-4f08-85df-827928c57e0b",
   "metadata": {},
   "source": [
    "### Part 2: How many stones would you have after blinking a total of 75 times?\n",
    "\n",
    "It looks like the number of stones is roughly doubling every 1 or 2 blinks, so for 75 blinks we could have trillions of stones. I'd like something more efficient. I note that:\n",
    "- Although the puzzle makes it clear that the stones are in a line, it turns out their position in the line is irrelevant.\n",
    "- Because all the even-digit numbers get split in half, it seems like many small numbers will appear multiple times.\n",
    "  - (In the given example, after 6 blinks the number 2 appears 4 times.)\n",
    "- Therefore, I'll keep a `Counter` of stones rather than a `list` of stones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "id": "707b5a97-0296-48df-bdab-e34064cc67c2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def blink2(stones: Ints, blinks=25) -> Counter:\n",
    "    \"\"\"Simulate the changes after blinking `blinks` times and return a Counter of stones.\"\"\"\n",
    "    counts = Counter(stones)\n",
    "    for _ in range(blinks):\n",
    "        counts = accumulate((s, counts[stone]) \n",
    "                            for stone in counts \n",
    "                            for s in change_stone(stone))\n",
    "    return counts"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f5bf07ce-b48e-40db-8992-b9b571e66554",
   "metadata": {},
   "source": [
    "Now we can re-run Part 1 (it should be slightly faster), and run Part 2 without fear of having trillion-element lists:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "id": "efdcdbf8-e8ec-4a85-9d09-90a20e08c66a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 11.1:   .002 seconds, answer 194482            ok"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(11.1, 194482, lambda:\n",
    "       total(blink2(stones, 25)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "id": "657b1f13-ffcc-44c6-84f1-398fa2fcdac7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 11.2:   .059 seconds, answer 232454623677743   ok"
      ]
     },
     "execution_count": 119,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(11.2, 232454623677743, lambda:\n",
    "       total(blink2(stones, 75)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce377749-b3e2-4ca4-b50d-e7c3d2e7201a",
   "metadata": {},
   "source": [
    "I'm glad I used the `Counter`; it would have taken a petabyte of storage (and a long, long time) to represent that many stones as a list.\n",
    "\n",
    "Again, I did pretty well, with no errors, and moving at what I thought was a good pace, but I didn't even crack the top 2000 on the leaderboard. \n",
    "\n",
    "### Part 3: Exploration\n",
    "\n",
    "Here I show how the stones grow, starting from a single stone marked \"0\" for 10 blinks, and how the total number of stones grows over 30 blinks."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "id": "8609fda3-c158-4fbb-bec5-4270c3a2dbe7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1]\n",
      "[2024]\n",
      "[20, 24]\n",
      "[2, 0, 2, 4]\n",
      "[4048, 1, 4048, 8096]\n",
      "[40, 48, 2024, 40, 48, 80, 96]\n",
      "[4, 0, 4, 8, 20, 24, 4, 0, 4, 8, 8, 0, 9, 6]\n",
      "[8096, 1, 8096, 16192, 2, 0, 2, 4, 8096, 1, 8096, 16192, 16192, 1, 18216, 12144]\n",
      "[80, 96, 2024, 80, 96, 32772608, 4048, 1, 4048, 8096, 80, 96, 2024, 80, 96, 32772608, 32772608, 2024, 36869184, 24579456]\n",
      "[8, 0, 9, 6, 20, 24, 8, 0, 9, 6, 3277, 2608, 40, 48, 2024, 40, 48, 80, 96, 8, 0, 9, 6, 20, 24, 8, 0, 9, 6, 3277, 2608, 3277, 2608, 20, 24, 3686, 9184, 2457, 9456]\n"
     ]
    }
   ],
   "source": [
    "S = [0]\n",
    "for _ in range(10):\n",
    "    S = blink(S, 1)\n",
    "    print(S)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "id": "100febf3-8397-4bce-a290-12de1f281f82",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1, 1, 2, 4, 4, 7, 14, 16, 20, 39, 62, 81, 110, 200, 328, 418, 667, 1059, 1546, 2377, 3572, 5602, 8268, 12343, 19778, 29165, 43726, 67724, 102131, 156451, "
     ]
    }
   ],
   "source": [
    "S = [0]\n",
    "for _ in range(30):\n",
    "    S = blink(S, 1)\n",
    "    print(len(S), end=', ')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "391cec1e-32fe-4e6e-81c2-4e38469b15e3",
   "metadata": {},
   "source": [
    "# [Day 12](https://adventofcode.com/2024/day/12): Garden Groups\n",
    "\n",
    "Today's input is yet another 2D map. This one depicts different garden **plots** on a farm, each plot planted with a **crop**, indicated by a letter. Perhaps \"I\" is iceberg lettuce, \"O\" is okra, \"A\" is avocado, and so on."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "id": "8161ee7e-76e3-499a-abf8-a607991c9602",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 140 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "IIIIIIIIIIIIIIIIIIIIIUUUUUUUUJLLLLAAAAAAMMMAUUUUPPXPZZZZZZZZZZZXXXXXXXXXXXXXXXXXXXXXFFFFFFFFFFZZ ...\n",
      "IIIIIIIIIIIIIIIIIIIIUUUUUUUUUJALEAAAAAAAAAAAAUUUUPXPPZZZZZHHHHHHXHXXXXXXXXXXXXXXXXXXFXFFFFFFFFZZ ...\n",
      "IIIIIIIIIIIIIIIIIIIIUUUUUUUUUJAAAAAAAAAAAAAAUUPPPPPPPZZZZZZZHHHHHHHXXXXXXXXXXXXXXXXXXXFFFFFFFFFZ ...\n",
      "IIIIIIIIIIIAAIIIIIIIIIUUUUUUUJJAAAAAAAAAAAAAAVVPPPPPPPPZHHHHHHHHHHHXXXXXXXXXXXXXXXXXFFFFFFFFFFFZ ...\n",
      "IOOIIIIIIIIAAIIIIIIIIIIUUUQVUJJAAAAAAAAAAAAAEVVZPPPPPPPHHHHHHHHHHHHXXXXXXXXXXXXXXXXXXXXFFFFFFLLL ...\n",
      "OOOOOOOOIIAAAAAIIIIIIIIUQQQQVQJAAAAAAAAAAAAAAVVPPPPPIIHHHHHHHHHHHHHXXXXXUXXXXXXUUXXBBBSFFFLLLLLL ...\n",
      "OOOOOOOOIAAAAAAIIIIIIQQQQQQQQQQQEADDAAAAAAAAHHVVPPPIIIIHHHHHHHHHHHHHXXXUUUUUXXUUUXXBBBSFFFLLELLL ...\n",
      "OOOOOOOOIIIAAIIIIIQQQQQQQQQQTQJQEEDDDAAAAAAHHVVVVPIIIIIHHHHHHHHHHHHHXUUUUUUUUUUUMMXBBBSSSFFFLLLL ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "farm = Grid(parse(12))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb95a10b-1f83-4940-a68b-b94696c3aab3",
   "metadata": {},
   "source": [
    "### Part 1: What is the total price of fencing all regions on your map?\n",
    "\n",
    "We are asked to calculate the cost of putting fences around each region. A **region** is a set of garden plots with the same crop that abut each other horizontally or vertically. The **price** of the fence for a region is defined as the product of the region's area and its perimeter. (That seems like a strange way to do pricing, but what do I know.) If we represent a region as a **set** of (x, y) points, then the area is easy: it is just the number of points. The perimeter can be computed by, for each plot point in the region, counting the neighbors (in the 4 directions) that are *not* in the region."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "id": "79f91f38-e325-44f2-9e53-b64ce12d9d35",
   "metadata": {},
   "outputs": [],
   "source": [
    "Region = Set[Point]\n",
    "region_area = len\n",
    "\n",
    "def fence_price(farm: Grid) -> int:\n",
    "    \"\"\"Total price of fences for all the regions in the farm.\"\"\"\n",
    "    return sum(map(region_price, all_regions(farm)))\n",
    "\n",
    "def region_price(region) -> int: return region_area(region) * perimeter_length(region)\n",
    "\n",
    "def perimeter_length(region: Region) -> int:\n",
    "    \"\"\"The number of sides on the perimeter of the region:\n",
    "    sides where the neighboring position in the given direction is not in the region.\"\"\"\n",
    "    return quantify(neighbor not in region \n",
    "                    for plot in region for neighbor in neighbors(plot))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9524ee15-c378-4cd4-a79b-14fb99b17cb3",
   "metadata": {},
   "source": [
    "To find all the regions I'll start at a point and do a [flood fill](https://en.wikipedia.org/wiki/Flood_fill) to neighboring points with the same region letter, keeping track of points that have already been found. The function `all_regions` iterates over all points to make sure it finds every region, and `flood_fill` recursively expands to all points that neighbor `p` and have the same crop (letter). `flood_fill` mutates the set `already_found` as it goes (and also mutates the `region` it is building up)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "id": "1fbabbfb-50c8-4197-8517-e7cee9582765",
   "metadata": {},
   "outputs": [],
   "source": [
    "def all_regions(farm: Grid) -> List[Region]:\n",
    "    \"\"\"Find all the regions in the farm.\"\"\"\n",
    "    already_found = set() # Set of plots already accounted for\n",
    "    return [flood_fill(p, farm, set(), already_found) \n",
    "            for p in farm if p not in already_found]\n",
    "\n",
    "def flood_fill(p: Point, grid: Grid, region: set, already_found: set) -> set:\n",
    "    \"\"\"Starting at point p, recursively add all neighboring points to `region`, keeping track of `already_found`.\"\"\"\n",
    "    if p not in already_found:\n",
    "        region.add(p)\n",
    "        already_found.add(p)\n",
    "        for p2 in grid.neighbors(p):\n",
    "            if farm[p2] == farm[p]:\n",
    "                flood_fill(p2, grid, region, already_found)\n",
    "    return region"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "id": "cdaf655b-d12c-4973-b19b-3132e5e691c6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 12.1:   .032 seconds, answer 1402544           ok"
      ]
     },
     "execution_count": 129,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(12.1, 1402544, lambda:\n",
    "       fence_price(farm))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3383560-2bbc-4dfc-b643-feb103876823",
   "metadata": {},
   "source": [
    "### Part 2: What is the total price of fencing all regions on your map, with the bulk discount?\n",
    "\n",
    "In Part 2 we get a **bulk discount** on the fencing; we only need to pay for the number of **straight line sides** on the perimeter, not the total length of the perimeter. For example, a 10 x 10 square has perimeter 40, but has only 4 sides. That's a 90% discount!\n",
    "\n",
    "It took me a while to figure out a good approach for this. At first I was reminded of the Convex Hull problem, for which I have [a notebook](https://github.com/norvig/pytudes/blob/main/ipynb/Convex%20Hull.ipynb). But that's not really appropriate here; our regions could be non-convex, and the set of sides in a region are not the same as the vertexes of a polygon (e.g., a region with one point has 4 sides, not 0). (*Funny story:* I wondered if an AI large language model (LLM) for programming would get confused like I did on this. So I described the problem in a way that hinted at convex hull, and the LLM suggested sorting the points by their angle to the centroid (a good idea for the convex hull problem), and then returning the length of the list of points. So, (1) that's not the right answer, and (2) if it was the right answer, it would have been right before sorting.)\n",
    "\n",
    "A better idea is to start with the perimeter length and subtract one for every case in which a point has an edge in one direction (e.g., an edge to the North) and also has a neighbor with the same edge. To be precise, I'll look for four cases:\n",
    "- A point with an edge to the North whose neighbor to the East also has an edge to the North\n",
    "- A point with an edge to the East whose neighbor to the South also has an edge to the East\n",
    "- A point with an edge to the South whose neighbor to the West also has an edge to the South\n",
    "- A point with an edge to the West whose neighbor to the North also has an edge to the West\n",
    "\n",
    "Here are two diagrams of two regions with two kinds of crop, \"`X`\" and \"`W`\", with a \"`-`\" marking each place where a perimeter piece would be subtracted.\n",
    "\n",
    "     .X-...    .-------..\n",
    "     -X-.X-    .WWWWWWWW-\n",
    "     -XXXX-    -WWWWWWWW-\n",
    "     ..XXX.    -WWWWWWWW.\n",
    "     ...--.    ..-------.\n",
    "\n",
    "I'll refactor `fence_price` to take a `region_price` parameter, and show that the change is backwards compatible to Part 1:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "id": "38c30e15-3a33-40c2-b734-163a15af7a8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "def fence_price(farm: Grid, region_price:Callable=region_price) -> int:\n",
    "    \"\"\"Total price of fences for all the regions in the farm, given the price function for a region.\"\"\"\n",
    "    return sum(map(region_price, all_regions(farm)))\n",
    "\n",
    "def discount_region_price(region) -> int: return region_area(region) * region_sides(region)\n",
    "    \n",
    "def region_sides(region):\n",
    "    \"\"\"How many straight-line sides does this region have?\n",
    "    The perimeter minus all sides that are the same as their clockwise neighbor.\"\"\"\n",
    "    def has_edge(p: Point, d: Vector): return p in region and add(p, d) not in region\n",
    "    def neighbor(p: Point, d: Vector): return add(p, make_turn(d, 'R'))\n",
    "    subtract = quantify(has_edge(p, d) and has_edge(neighbor(p, d), d)\n",
    "                        for p in region\n",
    "                        for d in directions4)\n",
    "    return perimeter_length(region) - subtract"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "id": "72175812-dcd0-4f1b-9efa-0dceeeafa609",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 12.1:   .050 seconds, answer 1402544           ok"
      ]
     },
     "execution_count": 132,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(12.1, 1402544, lambda:\n",
    "       fence_price(farm))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "id": "9defcd35-91bc-41d4-a16f-bb7a4ede75e7",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 12.2:   .043 seconds, answer 862486            ok"
      ]
     },
     "execution_count": 133,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(12.2, 862486, lambda: \n",
    "       fence_price(farm, discount_region_price))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "faa9d750-a619-40dc-965c-a9a8e2543e32",
   "metadata": {},
   "source": [
    "# [Day 13](https://adventofcode.com/2024/day/13): Claw Contraption\n",
    "\n",
    "Today's puzzle involves arcade claw machines. Each input paragraph describes a machine with two buttons, **A** and **B**; every push of a button moves the claw a specified amount in the X and Y directions (which is different for each machine). The prize is at a specified location (also different for each machine). We can parse the input by defining a `parse_claw` function and a `Claw` datatype to represent the machine.\n",
    "\n",
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/647/741/325/081/329/small/30d98922146765ad.jpg\" width=400>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "id": "e78f45c0-c420-4661-aad2-14e122b4473b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1279 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Button A: X+24, Y+19\n",
      "Button B: X+32, Y+86\n",
      "Prize: X=1072, Y=2062\n",
      "\n",
      "Button A: X+70, Y+12\n",
      "Button B: X+11, Y+43\n",
      "Prize: X=3400, Y=3872\n",
      "\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 320 Claws:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Claw(A=(24, 19), B=(32, 86), Prize=(1072, 2062))\n",
      "Claw(A=(70, 12), B=(11, 43), Prize=(3400, 3872))\n",
      "Claw(A=(48, 77), B=(34, 12), Prize=(6510, 1583))\n",
      "Claw(A=(76, 60), B=(29, 88), Prize=(5506, 6300))\n",
      "Claw(A=(16, 75), B=(68, 20), Prize=(17148, 13490))\n",
      "Claw(A=(46, 13), B=(33, 63), Prize=(15572, 9644))\n",
      "Claw(A=(21, 79), B=(44, 32), Prize=(2433, 5147))\n",
      "Claw(A=(13, 45), B=(36, 11), Prize=(4612, 19164))\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "Claw = namedtuple('Claw', 'A, B, Prize') # A claw machine\n",
    "\n",
    "def parse_claw(text: str) -> Claw:\n",
    "    \"\"\"Parse a paragraph of text into a Claw object.\"\"\"\n",
    "    ax, ay, bx, by, px, py = ints(text)\n",
    "    return Claw((ax, ay), (bx, by), (px, py))\n",
    "    \n",
    "claws = parse(13, parse_claw, sections=paragraphs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f6da888-9288-42f1-bc51-2eb2a66d34a1",
   "metadata": {},
   "source": [
    "### Part 1: What is the fewest tokens you would have to spend to win all possible prizes?\n",
    "\n",
    "We are told that for some machines it is possible to reach the prize and others it is impossible. We are also told that you need to spend 3 **tokens** to  press  the **A** button and 1 token to press the **B** button. There is a hint that no button will need to be pushed more than **100 times**. It is usually a good idea to accept the hint, so I will  do the following:\n",
    "- Exhaustively try every number from 0 to 100 presses of the **A** button.\n",
    "- For each number, figure out what the resulting position of the claw would be after those presses.\n",
    "- Calculate how many presses of the **B** button would be required to get to the prize's X location.\n",
    "- If the number of presses is an integer, and would also arrive at the prize's Y location, then yield that (A-presses, B-presses) solution.\n",
    "- Out of these solutions, the cheapest solution is  the one that needs the fewest tokens.\n",
    "- (If there are no solutions, `cheapest_solution` will return 0, whcih is convenient for adding the results up, but is worrisome because it doesn't distinguish between an impossible-to-reach prize and a prize at the origin. On this puzzle, that's ok, but it is still worrisome.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "id": "c2c4bbc9-42cd-483d-8da2-97cf051e93fe",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solve_claw(claw: Claw, limit=100) -> Iterable[Tuple[int, int]]:\n",
    "    \"\"\"All possible (A-presses, B-presses) solutions to reach the prize on this machine.\"\"\"\n",
    "    A, B, Prize = claw\n",
    "    for Apresses in range(limit + 1):\n",
    "        pos = mul(A, Apresses)\n",
    "        if X_(pos) > X_(Prize) or Y_(pos) > Y_(Prize):\n",
    "            return\n",
    "        diff = sub(Prize, pos)\n",
    "        Bpresses = X_(diff) / X_(B)\n",
    "        if Bpresses.is_integer() and Bpresses * Y_(B) == Y_(diff):\n",
    "            yield (Apresses, int(Bpresses))\n",
    "\n",
    "def cheapest_solution(claw: Claw) -> int: \n",
    "    \"\"\"The minimum cost out of every possible solution to this claw machine.\"\"\"\n",
    "    return min((3 * A + B for (A, B) in solve_claw(claw)), default=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "id": "f5638ed4-1e59-4b9f-b1fc-427d2eb0d036",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 13.1:   .006 seconds, answer 29598             ok"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(13.1, 29598, lambda:\n",
    "       sum(map(cheapest_solution, claws)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a36e76c-dd5b-4d80-ae88-9980e7d274ac",
   "metadata": {},
   "source": [
    "### Part 2: Using the corrected prize coordinates, what is the fewest tokens you would have to spend to win all possible prizes?\n",
    "\n",
    "In Part 2, we discover that \"due to a unit conversion error\" the prize is actually **much** farther away, by 10,000,000,000,000 (ten trillion) steps in both the X and Y coordinates. Theoretically, we could still use `solve_claw` with a bigger `limit`, but that would take a *long* time.\n",
    "Instead I can solve each claw machine *mathematically* rather than by trial and error. It looks like each claw machine defines two equations;  what exactly are the equations? For my first claw machine, \n",
    "\n",
    "     Button A: X+24, Y+19\n",
    "     Button B: X+32, Y+86\n",
    "     Prize: X=1072, Y=2062\n",
    "\n",
    "there are two linear equations to solve simultaneously, over the integers:\n",
    "\n",
    "     24 A + 32 B = 1072\n",
    "     19 A + 86 B = 2062\n",
    "\n",
    "I know that an equation over the integers is called a [Diophantine equation](https://en.wikipedia.org/wiki/Diophantine_equation), but I don't remember much about them, and furthermore it seems like it is more important that these are linear equations than that they are Diophantine equations. In general, two linear equations in two unknowns can have zero solutions (if the lines are parallel), an infinite number of solutions (if the lines are the same), or exactly one solution (the intersection of the lines;  the \"normal\" case). We can solve the linear equations, and then discard the answer if *A* and *B* are not integers. \n",
    "\n",
    "I defined `solve_claw` to yield multiple solutions, but let's see how many solutions each claw machine yields:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "id": "df8da2ae-52f9-409b-a54f-ad7d21b32e45",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({0: 168, 1: 152})"
      ]
     },
     "execution_count": 140,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Counter(quantify(solve_claw(c)) for c in claws)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f0f97d47-5741-4c6e-ae96-5b3161ee2e56",
   "metadata": {},
   "source": [
    "This says that 168 claw machines have no solution and 152 have exactly one solution. None of them have more than one solution.\n",
    "\n",
    "So, what is the intersection point of two lines? You could [look it up](https://www.wolframalpha.com/input?i=solve+for+a%2C+b%3A+p+*+a+%2B+q+*+b+%3D+r++and+++s+*+a+%2B+t+*+b+%3D+u) or work it out by hand, or [call a library function](https://numpy.org/doc/2.1/reference/generated/numpy.linalg.solve.html). Given the two equations over the variables *a* and *b*:\n",
    "\n",
    "    p * a + q * b = r\n",
    "    s * a + t * b = u\n",
    "\n",
    "The solution is:\n",
    "\n",
    "    a = (r * t - q * u) / (p * t - q * s)\n",
    "    b = (r * s - p * u) / (q * s - p * t)\n",
    "\n",
    "So we can rewrite `solve_claw` to use this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "id": "6bbd0934-d962-4c93-940b-810651e9e568",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solve_claw(claw: Claw) -> Iterable[Tuple[int, int]]:\n",
    "    \"\"\"All possible (A-presses, B-presses) solutions to reach the prize on this machine.\"\"\"\n",
    "    ((p, s), (q, t), (r, u)) = claw\n",
    "    a = (r * t - q * u) / (p * t - q * s)\n",
    "    b = (r * s - p * u) / (q * s - p * t)\n",
    "    if a.is_integer() and b.is_integer():\n",
    "        yield (int(a), int(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af52d98e-50e9-4c4d-875f-1ed2b3dc8111",
   "metadata": {},
   "source": [
    "This raises an interesting style question: If you have a function that might return zero or one result of type `T`, should you define the return type as `Optional[T]` or as `Iterable[T]`? I guess it depends on the expected use cases of the function.\n",
    "\n",
    "We'll need a way to move the prizes further away:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "id": "dd38ba4c-44ba-426b-b1c8-0e10adbdd642",
   "metadata": {},
   "outputs": [],
   "source": [
    "def move_prizes(claws, delta=(10**13, 10**13)) -> List[Claw]:\n",
    "    \"\"\"Move each claw's prize by the given displacement, delta.\"\"\"\n",
    "    return [claw._replace(Prize=(add(claw.Prize, delta))) for claw in claws]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "285bfa66-a33e-4d97-b7a7-cfd821953091",
   "metadata": {},
   "source": [
    "Now we can answer Part 2:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 146,
   "id": "9f578b3e-6b6d-4eb0-9228-c98122a84747",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 13.2:   .000 seconds, answer 93217456941970    ok"
      ]
     },
     "execution_count": 146,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(13.2, 93217456941970, lambda:\n",
    "       sum(map(cheapest_solution, move_prizes(claws))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "db917eed-07e5-4409-a92d-b26534a1fcd4",
   "metadata": {},
   "source": [
    "The refactored `solve_claw` is compatible with Part 1, and should be  faster:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "id": "609ed4ce-548c-4af4-8e09-c621aca0124e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 13.1:   .000 seconds, answer 29598             ok"
      ]
     },
     "execution_count": 148,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(13.1, 29598, lambda:\n",
    "       sum(map(cheapest_solution, claws)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "741bd221-cda4-432b-8ad2-b8c6950c7dc3",
   "metadata": {},
   "source": [
    "I could have recognized in Part 1 that we have a system of two linear equations in two unknowns, and implemented the Part 2 solution. But I have no regrets; I took the hint that trial-and-test for 100 trials was a good idea, and I saved the complicated algebra for when I really needed it in Part 2. Having two independent implementations that produce the same answer increases my confidence in both of them."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2576ce68-3f1e-4887-ab0b-62fa94cbe55a",
   "metadata": {},
   "source": [
    "# [Day 14](https://adventofcode.com/2024/day/14 ): Restroom Redoubt\n",
    "\n",
    "Today's narratives involve multiple robots roaming around a restroom. Each line of the input describes a robot's position and velocity in two dimensions:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "id": "1a5f5875-426d-47ea-a35a-405c39ced5dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 500 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "p=62,20 v=85,-14\n",
      "p=88,18 v=-70,97\n",
      "p=51,21 v=35,-22\n",
      "p=19,56 v=2,45\n",
      "p=93,11 v=-87,26\n",
      "p=90,67 v=44,-13\n",
      "p=99,34 v=82,57\n",
      "p=55,42 v=82,22\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 500 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(62, 20, 85, -14)\n",
      "(88, 18, -70, 97)\n",
      "(51, 21, 35, -22)\n",
      "(19, 56, 2, 45)\n",
      "(93, 11, -87, 26)\n",
      "(90, 67, 44, -13)\n",
      "(99, 34, 82, 57)\n",
      "(55, 42, 82, 22)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "robots = parse(14, ints) "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "818a939d-2038-4574-a20b-c1194d403f2c",
   "metadata": {},
   "source": [
    "### Part 1: What will the safety factor be after exactly 100 seconds have elapsed?\n",
    "\n",
    "Each second the  robots move according to their velocity, and they wrap around when they reach the edge of their world, which has width 101 and height 103. They never collide; they can pass right through each other. We're asked to figure out where they are after 100 seconds. I can see that it is not necessary to simulate the robots movements time step by time step; we can just multiply their velocity by time, add it to their initial position, and then take the result modulo the width or height. That's done in `robot_dance`. \n",
    "\n",
    "We're asked to figure out how many robots end up in each **quadrant**. There are four quadrants, but a robot that is exactly on a middle line, either horizontally or vertically, doesn't count in any quadrant. Finally, the **safety factor** is the product of the four counts of robots in each quadrant."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "id": "be22ac94-7401-4cf6-ab83-e43775536af7",
   "metadata": {},
   "outputs": [],
   "source": [
    "def robot_dance(robots, steps=100, width=101, height=103) -> List[Point]:\n",
    "    \"\"\"Move each robot for `steps` number of steps.\"\"\"\n",
    "    return [((x + steps * dx) % width, (y + steps * dy) % height)\n",
    "            for (x, y, dx, dy) in robots]\n",
    "\n",
    "def quadrant_counts(positions, w=101//2, h=103//2) -> Counter:\n",
    "    \"\"\"How many robots are in each quadrant? Ignore robots exactly in the middle.\"\"\"\n",
    "    return Counter((sign(x - w), sign(y - h)) \n",
    "                   for (x, y) in positions if x != w and y != h)\n",
    "\n",
    "def safety_factor(robots) -> int:\n",
    "    \"\"\"The product of the four counts of robots in each quadrant.\"\"\"\n",
    "    return prod(quadrant_counts(robot_dance(robots)).values())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "id": "69093001-79aa-463a-b801-51cd5b4de4eb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 14.1:   .000 seconds, answer 216027840         ok"
      ]
     },
     "execution_count": 154,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(14.1, 216027840, lambda:\n",
    "       safety_factor(robots))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "06b4e335-9863-40f7-983a-0744884dbc20",
   "metadata": {},
   "source": [
    "In case you're curious, here are the quadrant counts after 100 steps:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "id": "08661dc5-445c-4908-b0b4-57f3a53e5179",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({(1, 1): 124, (-1, 1): 122, (-1, -1): 120, (1, -1): 119})"
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "quadrant_counts(robot_dance(robots))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0cb27ad-82ff-4dcb-85cf-596b16ae9875",
   "metadata": {},
   "source": [
    "### Part 2: What is the fewest number of seconds that must elapse for the robots to display a picture of a Christmas Tree?\n",
    "\n",
    "I was **so** sure that Part 2 was going to ask for 10 trillion steps, and I was going to be **so** clever for not simulating step-by-step. But I was wrong. \n",
    "\n",
    "Instead we have the very vague task of discovering when a picture emerges. There is a hint that \"*very rarely, most of the robots should arrange themselves into a picture of a Christmas tree.*\" Since I don't know exactly how to specify a picture of a Christmas tree, I see three options:\n",
    "1) I could build an animation, and watch as each frame is displayed, stopping when I see something that looks like a tree.\n",
    "2) The phrase \"*most of the robots should arrange themselves*\" suggests that most of the robots are in one area. I could check for that.\n",
    "3) I could generate an image for each time step and send it off to an AI image recognition service. That would be iffy, slow, and probably expensive. \n",
    "\n",
    "I'll try the animation approach first. Google and Stack Overflow led me to the `matplotlib.animation.FuncAnimation` function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "id": "664c686e-0c3d-43b8-970f-88c0bf47dbf6",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.animation\n",
    "\n",
    "def animate_robots(robots, times: Ints):\n",
    "    \"\"\"Animate the robot dance over the given time steps.\"\"\"\n",
    "    plt.rcParams[\"animation.html\"] = \"jshtml\"\n",
    "    plt.rcParams['figure.dpi'] = 100  \n",
    "    plt.ioff()\n",
    "    fig, ax = plt.subplots()\n",
    "    def animate(t: int):\n",
    "        points = robot_dance(robots, t)\n",
    "        plt.cla()\n",
    "        ax.yaxis.set_inverted(True)\n",
    "        plt.plot(*T(points), 'go')\n",
    "        plt.title(f'{t} seconds')\n",
    "    plt.ion()\n",
    "    return matplotlib.animation.FuncAnimation(fig, animate, frames=times)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92048f28-a6a4-4c12-847f-62884177dec5",
   "metadata": {},
   "source": [
    "Here's what it looks like:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "id": "87843969-cb37-4fa5-9788-6a1b71c43521",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<link rel=\"stylesheet\"\n",
       "href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css\">\n",
       "<script language=\"javascript\">\n",
       "  function isInternetExplorer() {\n",
       "    ua = navigator.userAgent;\n",
       "    /* MSIE used to detect old browsers and Trident used to newer ones*/\n",
       "    return ua.indexOf(\"MSIE \") > -1 || ua.indexOf(\"Trident/\") > -1;\n",
       "  }\n",
       "\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    var slider = document.getElementById(this.slider_id);\n",
       "    slider.max = this.frames.length - 1;\n",
       "    if (isInternetExplorer()) {\n",
       "        // switch from oninput to onchange because IE <= 11 does not conform\n",
       "        // with W3C specification. It ignores oninput and onchange behaves\n",
       "        // like oninput. In contrast, Microsoft Edge behaves correctly.\n",
       "        slider.setAttribute('onchange', slider.getAttribute('oninput'));\n",
       "        slider.setAttribute('oninput', null);\n",
       "    }\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src =\n",
       "            this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function() {\n",
       "        t.anim_step_forward();\n",
       "    }, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function() {\n",
       "        t.anim_step_reverse();\n",
       "    }, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<style>\n",
       ".animation {\n",
       "    display: inline-block;\n",
       "    text-align: center;\n",
       "}\n",
       "input[type=range].anim-slider {\n",
       "    width: 374px;\n",
       "    margin-left: auto;\n",
       "    margin-right: auto;\n",
       "}\n",
       ".anim-buttons {\n",
       "    margin: 8px 0px;\n",
       "}\n",
       ".anim-buttons button {\n",
       "    padding: 0;\n",
       "    width: 36px;\n",
       "}\n",
       ".anim-state label {\n",
       "    margin-right: 8px;\n",
       "}\n",
       ".anim-state input {\n",
       "    margin: 0;\n",
       "    vertical-align: middle;\n",
       "}\n",
       "</style>\n",
       "\n",
       "<div class=\"animation\">\n",
       "  <img id=\"_anim_img6f0cd805e6024777a7d4c6f847e74e47\">\n",
       "  <div class=\"anim-controls\">\n",
       "    <input id=\"_anim_slider6f0cd805e6024777a7d4c6f847e74e47\" type=\"range\" class=\"anim-slider\"\n",
       "           name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\"\n",
       "           oninput=\"anim6f0cd805e6024777a7d4c6f847e74e47.set_frame(parseInt(this.value));\">\n",
       "    <div class=\"anim-buttons\">\n",
       "      <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.slower()\">\n",
       "          <i class=\"fa fa-minus\"></i></button>\n",
       "      <button title=\"First frame\" aria-label=\"First frame\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.first_frame()\">\n",
       "        <i class=\"fa fa-fast-backward\"></i></button>\n",
       "      <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.previous_frame()\">\n",
       "          <i class=\"fa fa-step-backward\"></i></button>\n",
       "      <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.reverse_animation()\">\n",
       "          <i class=\"fa fa-play fa-flip-horizontal\"></i></button>\n",
       "      <button title=\"Pause\" aria-label=\"Pause\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.pause_animation()\">\n",
       "          <i class=\"fa fa-pause\"></i></button>\n",
       "      <button title=\"Play\" aria-label=\"Play\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.play_animation()\">\n",
       "          <i class=\"fa fa-play\"></i></button>\n",
       "      <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.next_frame()\">\n",
       "          <i class=\"fa fa-step-forward\"></i></button>\n",
       "      <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.last_frame()\">\n",
       "          <i class=\"fa fa-fast-forward\"></i></button>\n",
       "      <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"anim6f0cd805e6024777a7d4c6f847e74e47.faster()\">\n",
       "          <i class=\"fa fa-plus\"></i></button>\n",
       "    </div>\n",
       "    <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_select6f0cd805e6024777a7d4c6f847e74e47\"\n",
       "          class=\"anim-state\">\n",
       "      <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_6f0cd805e6024777a7d4c6f847e74e47\"\n",
       "             >\n",
       "      <label for=\"_anim_radio1_6f0cd805e6024777a7d4c6f847e74e47\">Once</label>\n",
       "      <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_6f0cd805e6024777a7d4c6f847e74e47\"\n",
       "             checked>\n",
       "      <label for=\"_anim_radio2_6f0cd805e6024777a7d4c6f847e74e47\">Loop</label>\n",
       "      <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_6f0cd805e6024777a7d4c6f847e74e47\"\n",
       "             >\n",
       "      <label for=\"_anim_radio3_6f0cd805e6024777a7d4c6f847e74e47\">Reflect</label>\n",
       "    </form>\n",
       "  </div>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_img6f0cd805e6024777a7d4c6f847e74e47\";\n",
       "    var slider_id = \"_anim_slider6f0cd805e6024777a7d4c6f847e74e47\";\n",
       "    var loop_select_id = \"_anim_loop_select6f0cd805e6024777a7d4c6f847e74e47\";\n",
       "    var frames = new Array(3);\n",
       "    \n",
       "  frames[0] = \"\\\n",
       "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\\\n",
       "\"\n",
       "  frames[1] = \"\\\n",
       "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\\\n",
       "WpU4hnZ2xm9/+1vrvvvus37xi19YAKznnnsu6fcidr3jjjusAQMGWNu3b7feeusta+LEidZXvvIV\\\n",
       "q62tzePe+BcuAA3jqquusu64446kzy677DLr7rvv1tSi4HHixAkLgPXyyy9blmVZ7e3tVr9+/ayf\\\n",
       "/vSniWP+67/+y+rVq5f12GOP6Wqmb2lsbLSGDRtmbd++3bruuusSC0DaWQ533XWXde2112b8Pe0s\\\n",
       "h29/+9vWP/7jPyZ9Vl5ebs2ePduyLNpZFqkLQBG7/vnPf7YuuOAC65lnnkkcc/ToUatLly7WCy+8\\\n",
       "4Fnb/Q4lYINobW3Fm2++iSlTpiR9PmXKFNTX12tqVfA4e/YsAKCwsBAAcODAARw/fjzJ7vn5+bju\\\n",
       "uutodwf88Ic/xLe//W1MmjQp6XPaWQ6/+tWvMGbMGHznO99B3759MXr0aKxbty7xe9pZDtdeey12\\\n",
       "7NiBDz74AADwH//xH3jllVfwrW99CwDtrAoRu7755pv461//mnRM//79MXLkSNreBl11N4B8zqlT\\\n",
       "pxCLxVBcXJz0eXFxMY4fP66pVcHCsixUVVXh2muvxciRIwEgYdt0dv/44489b6OfeeaZZ/DWW2/h\\\n",
       "9ddf7/Q72lkOH330ER599FFUVVXh3nvvxWuvvYY777wT+fn5+N73vkc7S+Kuu+7C2bNncdlllyEa\\\n",
       "jSIWi+EnP/kJZs6cCYD+rAoRux4/fhx5eXm46KKLOh3DZ6U4XAAaSCQSSfq/ZVmdPiPO+NGPfoR3\\\n",
       "330Xr7zySqff0e7uOHz4MObPn48XX3wRF154YcbjaGd3tLe3Y8yYMVi2bBkAYPTo0fjP//xPPPro\\\n",
       "o/je976XOI52dsemTZvw1FNPYcOGDbj88svxzjvvoKKiAv3798ett96aOI52VoMTu9L29qAEbBBF\\\n",
       "RUWIRqOd/oI5ceJEp7+GiH3mzZuHX/3qV9i5cycGDhyY+Lxfv34AQLu75M0338SJEydw5ZVXomvX\\\n",
       "rujatStefvll/PznP0fXrl0TtqSd3XHxxRfjy1/+ctJnI0aMwKFDhwDQn2WxcOFC3H333bj55psx\\\n",
       "atQofPe730VlZSWWL18OgHZWhYhd+/Xrh9bWVpw5cybjMSQ3XAAaRF5eHq688kps37496fPt27dj\\\n",
       "3LhxmlrlfyzLwo9+9CNs2bIFv/vd73DppZcm/f7SSy9Fv379kuze2tqKl19+mXa3QWlpKfbs2YN3\\\n",
       "3nkn8TNmzBjMmjUL77zzDoYOHUo7S+DrX/96pzRGH3zwAS655BIA9GdZNDU1oUuX5EdkNBpNpIGh\\\n",
       "ndUgYtcrr7wSF1xwQdIxx44dw969e2l7O2jbfkLSEk8D8/jjj1vvvfeeVVFRYXXv3t06ePCg7qb5\\\n",
       "lh/84AdWr169rLq6OuvYsWOJn6ampsQxP/3pT61evXpZW7Zssfbs2WPNnDmT6Rwk0HEXsGXRzjJ4\\\n",
       "7bXXrK5du1o/+clPrA8//NB6+umnrYKCAuupp55KHEM7u+fWW2+1BgwYkEgDs2XLFquoqMiqrq5O\\\n",
       "HEM7O6OxsdF6++23rbffftsCYNXW1lpvv/12It2ZiF3vuOMOa+DAgdZLL71kvfXWW9Y3vvENpoGx\\\n",
       "CReABvLII49Yl1xyiZWXl2d97WtfS6QrIc4AkPbniSeeSBzT3t5u3X///Va/fv2s/Px862//9m+t\\\n",
       "PXv26Gt0QEhdANLOcvj1r39tjRw50srPz7cuu+wya+3atUm/p53dc+7cOWv+/PnW4MGDrQsvvNAa\\\n",
       "OnSodd9991ktLS2JY2hnZ+zcuTPtnHzrrbdaliVm1+bmZutHP/qRVVhYaHXr1s264YYbrEOHDmno\\\n",
       "jX+JWJZl6Xn3SAghhBBCdMAYQEIIIYSQkMEFICGEEEJIyOACkBBCCCEkZHABSAghhBASMrgAJIQQ\\\n",
       "QggJGVwAEkIIIYSEDC4ACSGEEEJCBheAhBBCCCEhgwtAQgghhJCQwQUgIYQQQkjI4AKQEEIIISRk\\\n",
       "cAFICCGEEBIyuAAkhBBCCAkZXAASQgghhIQMLgAJIYQQQkIGF4CEEEIIISGDC0BCCCGEkJDBBSAh\\\n",
       "hBBCSMjgApAQQgghJGRwAUgIIYQQEjK4ACSEEEIICRlcABJCCCGEhAwuAAkhhBBCQgYXgIQQQggh\\\n",
       "IYMLQEIIIYSQkMEFICGEEEJIyOACkBBCCCEkZHABSAghhBASMrgAJIQQQggJGVwAEkIIIYSEDC4A\\\n",
       "CSGEEEJCxv8HKptaBcFgKWcAAAAASUVORK5CYII=\\\n",
       "\"\n",
       "  frames[2] = \"\\\n",
       "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\\\n",
       "BlAzvvSlL1nf/e53k3520UUXWffdd59PLQoeR44csQBYr732mmVZltXR0WEVFxdbP/nJTxLX/PWv\\\n",
       "f7V69+5tPfXUU34101iam5utoUOHWnV1ddY111yT2ADSznL4wQ9+YH3lK1/J+HvaWQ7XX3+99Z3v\\\n",
       "fCfpZ1OmTLFuvfVWy7JoZ1mkbgBF7Ppf//Vf1llnnWU9//zziWsaGxutbt26WS+//LJnbTcdSsAa\\\n",
       "0dbWhq1bt2LSpElJP580aRIaGhp8alXwOHnyJACgqKgIAPDhhx/i8OHDSXbPz8/HNddcQ7s74K67\\\n",
       "7sL111+PCRMmJP2cdpbDr3/9a4waNQrf+MY30L9/f4wcORLPPPNM4ve0sxy+8pWvYOPGjfjzn/8M\\\n",
       "APjP//xP/OEPf8DXvvY1ALSzKkTsunXrVvztb39LumbgwIEYPnw4bW+D7n43gHzGsWPHEIvFMGDA\\\n",
       "gKSfDxgwAIcPH/apVcHCsixUVVXhK1/5CoYPHw4ACdums/tHH33keRtN5vnnn8e2bdvw9ttvd/kd\\\n",
       "7SyHPXv24Mknn0RVVRV++MMf4q233sL3vvc95Ofn49vf/jbtLIkf/OAHOHnyJC666CJEo1HEYjH8\\\n",
       "+Mc/xvTp0wHQn1UhYtfDhw8jLy8P5557bpdr+F0pDjeAGhKJRJL+27KsLj8jzrj77rvx3nvv4Q9/\\\n",
       "+EOX39Hu7ti/fz9mzZqFDRs24Oyzz854He3sjo6ODowaNQrz588HAIwcORJ//OMf8eSTT+Lb3/52\\\n",
       "4jra2R2rV6/GihUrsHLlSlx66aV49913UVFRgYEDB+K2225LXEc7q8GJXWl7e1AC1oi+ffsiGo12\\\n",
       "+QvmyJEjXf4aIva555578Otf/xqbNm3CoEGDEj8vLi4GANrdJVu3bsWRI0dwxRVXoHv37ujevTte\\\n",
       "e+01PProo+jevXvClrSzO8477zxccsklST+7+OKLsW/fPgD0Z1nMnj0b9913H26++WaMGDEC3/rW\\\n",
       "t1BZWYkFCxYAoJ1VIWLX4uJitLW14cSJExmvIbnhBlAj8vLycMUVV6Curi7p53V1dRg9erRPrTIf\\\n",
       "y7Jw9913Y+3atXj11Vdx4YUXJv3+wgsvRHFxcZLd29ra8Nprr9HuNhg/fjy2b9+Od999N/Fv1KhR\\\n",
       "mDFjBt59910MGTKEdpbAl7/85S5pjP785z/jggsuAEB/lkVLSwu6dUv+ioxGo4k0MLSzGkTsesUV\\\n",
       "V+Css85KuubQoUPYsWMHbW8H346fkLTE08D87Gc/s95//32roqLC6tGjh7V3716/m2Ys//Iv/2L1\\\n",
       "7t3bqq+vtw4dOpT419LSkrjmJz/5idW7d29r7dq11vbt263p06cznYMEOp8CtizaWQZvvfWW1b17\\\n",
       "d+vHP/6xtWvXLuu5556zCgsLrRUrViSuoZ3dc9ttt1klJSWJNDBr1661+vbta1VXVyeuoZ2d0dzc\\\n",
       "bL3zzjvWO++8YwGwFi9ebL3zzjuJdGcidv3ud79rDRo0yHrllVesbdu2WV/96leZBsYm3ABqyBNP\\\n",
       "PGFdcMEFVl5ennX55Zcn0pUQZwBI++8Xv/hF4pqOjg7roYcesoqLi638/Hzrf/yP/2Ft377dv0YH\\\n",
       "hNQNIO0sh9/85jfW8OHDrfz8fOuiiy6ynn766aTf087uOXXqlDVr1izr/PPPt84++2xryJAh1gMP\\\n",
       "PGCdPn06cQ3t7IxNmzalXZNvu+02y7LE7Nra2mrdfffdVlFRkVVQUGDdcMMN1r59+3zojblELMuy\\\n",
       "/Hn3SAghhBBC/IAxgIQQQgghIYMbQEIIIYSQkMENICGEEEJIyOAGkBBCCCEkZHADSAghhBASMrgB\\\n",
       "JIQQQggJGdwAEkIIIYSEDG4ACSGEEEJCBjeAhBBCCCEhgxtAQgghhJCQwQ0gIYQQQkjI4AaQEEII\\\n",
       "ISRkcANICCGEEBIyuAEkhBBCCAkZ3AASQgghhIQMbgAJIYQQQkIGN4CEEEIIISGDG0BCCCGEkJDB\\\n",
       "DSAhhBBCSMjgBpAQQgghJGRwA0gIIYQQEjK4ASSEEEIICRncABJCCCGEhAxuAAkhhBBCQgY3gIQQ\\\n",
       "QgghIYMbQEIIIYSQkMENICGEEEJIyOAGkBBCCCEkZHADSAghhBASMrgBJIQQQggJGdwAEkIIIYSE\\\n",
       "jP8PE1yu61RT0JYAAAAASUVORK5CYII=\\\n",
       "\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        anim6f0cd805e6024777a7d4c6f847e74e47 = new Animation(frames, img_id, slider_id, 200.0,\n",
       "                                 loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<matplotlib.animation.FuncAnimation at 0x137ead7f0>"
      ]
     },
     "execution_count": 160,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "animate_robots(robots, range(3))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f722d21-dc5e-473c-b9d1-c71915cbeb6f",
   "metadata": {},
   "source": [
    "The animations take up a lot of space in the stored `.ipynb` file, so I only show 3 frames here. I looked at hundreds of frames, but no Christmas tree emerged. \n",
    "\n",
    "So, on to the second idea. If the hint had mentioned \"*all of the robots*\", I would look for an image frame with the minimum bounding box. But for \"*most of the robots*,\" I'll look for a frame that minimizes the mean distance from the centroid.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "id": "9563d49c-54a3-439f-a833-f48c2a070609",
   "metadata": {},
   "outputs": [],
   "source": [
    "def mean_distance_to_centroid(points, distance=taxi_distance) -> float:\n",
    "    \"\"\"The mean of each point's distance to the centroid.\"\"\"\n",
    "    centroid = (mean(Xs(points)), mean(Ys(points)))\n",
    "    return mean(distance(p, centroid) for p in points)\n",
    "\n",
    "def most_clustered_time(robots, times=range(10_000)) -> int:\n",
    "    \"\"\"Out of all the given time steps, the one that has the robots clustered closest together.\"\"\"\n",
    "    return min(times, key=lambda t: mean_distance_to_centroid(robot_dance(robots, t)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "id": "ab8c7e3b-f400-4976-ad0d-5f92cbadec02",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<link rel=\"stylesheet\"\n",
       "href=\"https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css\">\n",
       "<script language=\"javascript\">\n",
       "  function isInternetExplorer() {\n",
       "    ua = navigator.userAgent;\n",
       "    /* MSIE used to detect old browsers and Trident used to newer ones*/\n",
       "    return ua.indexOf(\"MSIE \") > -1 || ua.indexOf(\"Trident/\") > -1;\n",
       "  }\n",
       "\n",
       "  /* Define the Animation class */\n",
       "  function Animation(frames, img_id, slider_id, interval, loop_select_id){\n",
       "    this.img_id = img_id;\n",
       "    this.slider_id = slider_id;\n",
       "    this.loop_select_id = loop_select_id;\n",
       "    this.interval = interval;\n",
       "    this.current_frame = 0;\n",
       "    this.direction = 0;\n",
       "    this.timer = null;\n",
       "    this.frames = new Array(frames.length);\n",
       "\n",
       "    for (var i=0; i<frames.length; i++)\n",
       "    {\n",
       "     this.frames[i] = new Image();\n",
       "     this.frames[i].src = frames[i];\n",
       "    }\n",
       "    var slider = document.getElementById(this.slider_id);\n",
       "    slider.max = this.frames.length - 1;\n",
       "    if (isInternetExplorer()) {\n",
       "        // switch from oninput to onchange because IE <= 11 does not conform\n",
       "        // with W3C specification. It ignores oninput and onchange behaves\n",
       "        // like oninput. In contrast, Microsoft Edge behaves correctly.\n",
       "        slider.setAttribute('onchange', slider.getAttribute('oninput'));\n",
       "        slider.setAttribute('oninput', null);\n",
       "    }\n",
       "    this.set_frame(this.current_frame);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.get_loop_state = function(){\n",
       "    var button_group = document[this.loop_select_id].state;\n",
       "    for (var i = 0; i < button_group.length; i++) {\n",
       "        var button = button_group[i];\n",
       "        if (button.checked) {\n",
       "            return button.value;\n",
       "        }\n",
       "    }\n",
       "    return undefined;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.set_frame = function(frame){\n",
       "    this.current_frame = frame;\n",
       "    document.getElementById(this.img_id).src =\n",
       "            this.frames[this.current_frame].src;\n",
       "    document.getElementById(this.slider_id).value = this.current_frame;\n",
       "  }\n",
       "\n",
       "  Animation.prototype.next_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.previous_frame = function()\n",
       "  {\n",
       "    this.set_frame(Math.max(0, this.current_frame - 1));\n",
       "  }\n",
       "\n",
       "  Animation.prototype.first_frame = function()\n",
       "  {\n",
       "    this.set_frame(0);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.last_frame = function()\n",
       "  {\n",
       "    this.set_frame(this.frames.length - 1);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.slower = function()\n",
       "  {\n",
       "    this.interval /= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.faster = function()\n",
       "  {\n",
       "    this.interval *= 0.7;\n",
       "    if(this.direction > 0){this.play_animation();}\n",
       "    else if(this.direction < 0){this.reverse_animation();}\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_forward = function()\n",
       "  {\n",
       "    this.current_frame += 1;\n",
       "    if(this.current_frame < this.frames.length){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.first_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.last_frame();\n",
       "        this.reverse_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.last_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.anim_step_reverse = function()\n",
       "  {\n",
       "    this.current_frame -= 1;\n",
       "    if(this.current_frame >= 0){\n",
       "      this.set_frame(this.current_frame);\n",
       "    }else{\n",
       "      var loop_state = this.get_loop_state();\n",
       "      if(loop_state == \"loop\"){\n",
       "        this.last_frame();\n",
       "      }else if(loop_state == \"reflect\"){\n",
       "        this.first_frame();\n",
       "        this.play_animation();\n",
       "      }else{\n",
       "        this.pause_animation();\n",
       "        this.first_frame();\n",
       "      }\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.pause_animation = function()\n",
       "  {\n",
       "    this.direction = 0;\n",
       "    if (this.timer){\n",
       "      clearInterval(this.timer);\n",
       "      this.timer = null;\n",
       "    }\n",
       "  }\n",
       "\n",
       "  Animation.prototype.play_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = 1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function() {\n",
       "        t.anim_step_forward();\n",
       "    }, this.interval);\n",
       "  }\n",
       "\n",
       "  Animation.prototype.reverse_animation = function()\n",
       "  {\n",
       "    this.pause_animation();\n",
       "    this.direction = -1;\n",
       "    var t = this;\n",
       "    if (!this.timer) this.timer = setInterval(function() {\n",
       "        t.anim_step_reverse();\n",
       "    }, this.interval);\n",
       "  }\n",
       "</script>\n",
       "\n",
       "<style>\n",
       ".animation {\n",
       "    display: inline-block;\n",
       "    text-align: center;\n",
       "}\n",
       "input[type=range].anim-slider {\n",
       "    width: 374px;\n",
       "    margin-left: auto;\n",
       "    margin-right: auto;\n",
       "}\n",
       ".anim-buttons {\n",
       "    margin: 8px 0px;\n",
       "}\n",
       ".anim-buttons button {\n",
       "    padding: 0;\n",
       "    width: 36px;\n",
       "}\n",
       ".anim-state label {\n",
       "    margin-right: 8px;\n",
       "}\n",
       ".anim-state input {\n",
       "    margin: 0;\n",
       "    vertical-align: middle;\n",
       "}\n",
       "</style>\n",
       "\n",
       "<div class=\"animation\">\n",
       "  <img id=\"_anim_img9f8ef744d7ae49c1bb25688c6c5b7e4a\">\n",
       "  <div class=\"anim-controls\">\n",
       "    <input id=\"_anim_slider9f8ef744d7ae49c1bb25688c6c5b7e4a\" type=\"range\" class=\"anim-slider\"\n",
       "           name=\"points\" min=\"0\" max=\"1\" step=\"1\" value=\"0\"\n",
       "           oninput=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.set_frame(parseInt(this.value));\">\n",
       "    <div class=\"anim-buttons\">\n",
       "      <button title=\"Decrease speed\" aria-label=\"Decrease speed\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.slower()\">\n",
       "          <i class=\"fa fa-minus\"></i></button>\n",
       "      <button title=\"First frame\" aria-label=\"First frame\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.first_frame()\">\n",
       "        <i class=\"fa fa-fast-backward\"></i></button>\n",
       "      <button title=\"Previous frame\" aria-label=\"Previous frame\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.previous_frame()\">\n",
       "          <i class=\"fa fa-step-backward\"></i></button>\n",
       "      <button title=\"Play backwards\" aria-label=\"Play backwards\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.reverse_animation()\">\n",
       "          <i class=\"fa fa-play fa-flip-horizontal\"></i></button>\n",
       "      <button title=\"Pause\" aria-label=\"Pause\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.pause_animation()\">\n",
       "          <i class=\"fa fa-pause\"></i></button>\n",
       "      <button title=\"Play\" aria-label=\"Play\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.play_animation()\">\n",
       "          <i class=\"fa fa-play\"></i></button>\n",
       "      <button title=\"Next frame\" aria-label=\"Next frame\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.next_frame()\">\n",
       "          <i class=\"fa fa-step-forward\"></i></button>\n",
       "      <button title=\"Last frame\" aria-label=\"Last frame\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.last_frame()\">\n",
       "          <i class=\"fa fa-fast-forward\"></i></button>\n",
       "      <button title=\"Increase speed\" aria-label=\"Increase speed\" onclick=\"anim9f8ef744d7ae49c1bb25688c6c5b7e4a.faster()\">\n",
       "          <i class=\"fa fa-plus\"></i></button>\n",
       "    </div>\n",
       "    <form title=\"Repetition mode\" aria-label=\"Repetition mode\" action=\"#n\" name=\"_anim_loop_select9f8ef744d7ae49c1bb25688c6c5b7e4a\"\n",
       "          class=\"anim-state\">\n",
       "      <input type=\"radio\" name=\"state\" value=\"once\" id=\"_anim_radio1_9f8ef744d7ae49c1bb25688c6c5b7e4a\"\n",
       "             >\n",
       "      <label for=\"_anim_radio1_9f8ef744d7ae49c1bb25688c6c5b7e4a\">Once</label>\n",
       "      <input type=\"radio\" name=\"state\" value=\"loop\" id=\"_anim_radio2_9f8ef744d7ae49c1bb25688c6c5b7e4a\"\n",
       "             checked>\n",
       "      <label for=\"_anim_radio2_9f8ef744d7ae49c1bb25688c6c5b7e4a\">Loop</label>\n",
       "      <input type=\"radio\" name=\"state\" value=\"reflect\" id=\"_anim_radio3_9f8ef744d7ae49c1bb25688c6c5b7e4a\"\n",
       "             >\n",
       "      <label for=\"_anim_radio3_9f8ef744d7ae49c1bb25688c6c5b7e4a\">Reflect</label>\n",
       "    </form>\n",
       "  </div>\n",
       "</div>\n",
       "\n",
       "\n",
       "<script language=\"javascript\">\n",
       "  /* Instantiate the Animation class. */\n",
       "  /* The IDs given should match those used in the template above. */\n",
       "  (function() {\n",
       "    var img_id = \"_anim_img9f8ef744d7ae49c1bb25688c6c5b7e4a\";\n",
       "    var slider_id = \"_anim_slider9f8ef744d7ae49c1bb25688c6c5b7e4a\";\n",
       "    var loop_select_id = \"_anim_loop_select9f8ef744d7ae49c1bb25688c6c5b7e4a\";\n",
       "    var frames = new Array(1);\n",
       "    \n",
       "  frames[0] = \"\\\n",
       "bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9h\\\n",
       "AAAPYQGoP6dpAABT7klEQVR4nO3de3hV1Z3/8c8hQAiYREBNDAkGfBCpeKsoDoqQ4aJVnDgZegGt\\\n",
       "2P6qUJQSbEdUOiNaBbFVYVS02lapFtSpwdtYFC1BLDoqaov3qlAugnhBgoCgyfr94ZzIIefk3PY5\\\n",
       "e629368+eZ56snPO2muvffZifb9rrYgxxggAAACh0cHvAgAAACC/6AACAACEDB1AAACAkKEDCAAA\\\n",
       "EDJ0AAEAAEKGDiAAAEDI0AEEAAAIGTqAAAAAIUMHEAAAIGToAAIAAIQMHUAAAICQoQMIAAAQMnQA\\\n",
       "AQAAQoYOIAAAQMjQAQQAAAgZOoAAAAAhQwcQAAAgZOgAAgAAhAwdQAAAgJChAwgAABAydAABAABC\\\n",
       "hg4gAABAyNABBAAACBk6gAAAACFDBxAAACBk6AACAACEDB1AAACAkKEDCAAAEDJ0AAEAAEKGDiAA\\\n",
       "AEDI0AEEAAAIGTqAAAAAIUMHEAAAIGToAAIAAIQMHUAAAICQoQMIAAAQMnQAAWTlmWee0emnn67u\\\n",
       "3burqKhI/fr10y9+8YuYY4wxuuOOO3TccceppKREPXv21LBhw/Q///M/McfdddddikQiCX+uvfba\\\n",
       "Np//0EMPadiwYSopKVG3bt10xBFH6Pbbb8/pOdsuEolo5syZfhcDgMXoAALI2MKFCzVs2DCVlpbq\\\n",
       "97//vR577DFNnz5dxpiY46644gpdcMEFOuGEE/TAAw/orrvuUmFhocaMGaOGhobW48444ww9++yz\\\n",
       "bX5GjRolSfrXf/3XmPe99tprVVdXp4EDB+r+++/Xww8/rMmTJ2vPnj25P3kAcFjE7PtNDQAp2Lhx\\\n",
       "o/r3769zzz1X8+fPb/fYyspK9enTRytWrGh97fPPP1d5ebmGDRumhx56KOHf7tixQ+Xl5TrmmGNi\\\n",
       "/n7VqlU64YQTNHv2bF1yySXZn1CARCIRXXHFFYwCAkiIEUAAGfnNb36jHTt2aPr06UmP7dSpk0pL\\\n",
       "S2Ne69KlS+tPe+677z599tln+tGPfhTz+s0336zCwkJNmTIl/cJLevnllzVmzBgddNBBKiwsVEVF\\\n",
       "hc444wxt2LCh9RhjjObPn69jjjlGRUVF6t69u8aOHav33nuvzfstWbJEI0aMUGlpqbp27aoBAwZo\\\n",
       "9uzZMcc8/PDD+qd/+id17dpVxcXFGjVqlJ599tmYY2bOnKlIJKLXXntN48aNU2lpqcrKyvTDH/5Q\\\n",
       "27Ztizm2qalJ559/vnr27Kn99ttPp512mt5+++02Zfvwww91wQUXqKqqSoWFhTrwwAN10kkn6ckn\\\n",
       "n8yo7gC4jw4ggIw8/fTT6tGjh958800dc8wx6tixow466CBNmjRJTU1NMcdOnTpVS5Ys0W9/+1tt\\\n",
       "3bpVmzZt0sUXX6xt27bpJz/5Sbuf89vf/lYlJSX69re/3ebzBwwYoAceeED9+/dXQUGBKisrdeml\\\n",
       "lyYNAe/YsUOjRo3SBx98oFtuuUVLly7V3Llz1bt3b23fvr31uIkTJ6q+vl4jR47Ugw8+qPnz5+u1\\\n",
       "117TkCFD9MEHH8SU8fTTT1dLS4tuu+02PfLII/rJT34S05lcuHChamtrVVJSokWLFrXWxfDhw/XM\\\n",
       "M8+0KeO//du/6bDDDtMDDzygSy+9VAsXLtS0adNaf2+M0VlnnaW7775bP/3pT7V48WKdeOKJ+ta3\\\n",
       "vtXmvb7//e/rwQcf1H/+53/qiSee0G9+8xuNHDlSH3/8cbv1BCDADABkoH///qZLly6muLjYzJo1\\\n",
       "yyxbtsxcd911pqioyJx00kmmpaUl5vjbbrvNFBYWGklGkunRo4dZunRpu5/xxhtvGElm4sSJbX5X\\\n",
       "WFhoiouLTffu3c3NN99s/vznP5sZM2aYgoICM378+Hbf98UXXzSSzIMPPpjwmGeffdZIMtdff33M\\\n",
       "6+vXrzdFRUXmkksuMcYYs337dlNSUmJOPvnkNucc1dzcbCoqKsyRRx5pmpubW1/fvn27Oeigg8yQ\\\n",
       "IUNaX7viiiuMJHPdddfFvMfkyZNNly5dWj/jT3/6k5Fk5s2bF3PcNddcYySZK664ovW1/fbbz9TX\\\n",
       "17dTIwDChg4ggIz069fPSDKzZ8+OeX3u3LlGUkzn7ne/+50pLCw0P/3pT82TTz5pHnvsMfO9733P\\\n",
       "dO3a1SxZsiThZ/zsZz8zkswLL7zQ5nedOnUyksyiRYtiXq+vrzeSzN///veE7/vpp5+a7t27m/79\\\n",
       "+5tbb73VvPbaa22OmTFjholEIuaDDz4wX3zxRczPiSeeaE444QRjjDGPP/64kWQWLlyY8PNef/31\\\n",
       "uJ06Y4z58Y9/bDp06GB27NhhjPm6A/jmm2/GHHfbbbcZSWbz5s3GGGMuueQSI8l89NFHMcetWbOm\\\n",
       "TQfwn//5n83+++9vfvGLX5hnn33W7NmzJ2FZAYQDIWAAGenZs6ck6dRTT415PRqCfOmllyRJW7du\\\n",
       "1YUXXqgf/ehH+tWvfqURI0boW9/6lhYtWqTjjz9ekyZNivv+X3zxhX7/+9/r6KOP1qBBgzL+/HhK\\\n",
       "S0u1fPlyHXPMMbr88st1xBFHqKKiQldccYW++OILSdIHH3wgY4zKysrUqVOnmJ/nnntOH330kaSv\\\n",
       "8uukrya6JBINtR588MFtfldRUaGWlhZt3bo17vlFFRYWSpJ27drV+p4dO3Zsc1x5eXmbz7jvvvs0\\\n",
       "YcIE/eY3v9E//dM/qUePHjr33HO1efPmhGUGEGwd/S4AADcdddRReu6559q8bv5vYYEOHb769+Vb\\\n",
       "b72lXbt26fjjj29z7KBBg7R8+XJ99tln2m+//WJ+9+ijj2rLli36j//4j4SfH68Ds+/nJ3LkkUfq\\\n",
       "3nvvlTFGf/vb33TXXXfpqquuUlFRkS699FIdcMABikQiWrFiRWvna2/R1w488EBJisn321e0k7Zp\\\n",
       "06Y2v3v//ffVoUMHde/evd3yxnvPL7/8Uh9//HFMJzBenRxwwAGaO3eu5s6dq3Xr1unhhx/WpZde\\\n",
       "qi1btmjJkiVpfS6AYGAEEEBG/u3f/k2S9Kc//Snm9ccee0ySdOKJJ0r6aoRLUpvOojFGzz33nLp3\\\n",
       "765u3bq1ef/f/va36tKli84+++y0P79Dhw5xO5zxRCIRHX300brxxhu1//77t44cjhkzRsYYbdy4\\\n",
       "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\\\n",
       "avDgwbrllls0cODA1mM///xz/fu//7sWLlyoXbt2acSIEZo/f35aEzuYRm4Pl5c1cG3nC8Ryue0h\\\n",
       "PPieicXz29EOoC1oQPBKdHaepLibtjOiBCBbfM98jee3oyFgIGgIJwLINb5nsDdGALPAvyDgNcKJ\\\n",
       "AHKN7xme31IAdwIBXGbrzhcAgoPvGUiEgAEAAEKHDiAAAEDI0AEEAAAIGTqAAAAAIUMHEAAAIGTo\\\n",
       "AAIAAIQMHUAAAICQoQMIAAAQMnQAAQAAQoadQLIQ3UWvqanJ55IAAIBURZ/bYd4Nlw5gFrZv3y5J\\\n",
       "qqqq8rkkAAAgXdu3b1dpaanfxfBFxIS5+5ullpYWvf/++youLlYkEvH0vZuamlRVVaX169eHdqPq\\\n",
       "fKGu84e6zh/qOn+o6/zxqq6NMdq+fbsqKirUoUM4s+EYAcxChw4dVFlZmdPPKCkp4QslT6jr/KGu\\\n",
       "84e6zh/qOn+8qOuwjvxFhbPbCwAAEGJ0AAEAAEKGDqClCgsLdcUVV6iwsNDvogQedZ0/1HX+UNf5\\\n",
       "Q13nD3XtHSaBAAAAhAwjgAAAACFDBxAAACBk6AACAACEDB1AAACAkKEDaKH58+erT58+6tKli447\\\n",
       "7jitWLHC7yI5b/bs2Tr++ONVXFysgw46SGeddZbeeuutmGOMMZo5c6YqKipUVFSk4cOH67XXXvOp\\\n",
       "xMExe/ZsRSIR1dfXt75GXXtn48aNOuecc9SzZ0917dpVxxxzjFatWtX6e+raG19++aV+/vOfq0+f\\\n",
       "PioqKlLfvn111VVXqaWlpfUY6jozTz/9tM4880xVVFQoEonowQcfjPl9KvW6e/duTZkyRQcccIC6\\\n",
       "deumf/mXf9GGDRvyeBYOMrDKvffeazp16mTuuOMO8/rrr5upU6eabt26mX/84x9+F81pp556qrnz\\\n",
       "zjvNq6++al555RVzxhlnmN69e5vPPvus9Zhrr73WFBcXmwceeMCsXr3afPe73zUHH3ywaWpq8rHk\\\n",
       "bnv++edNdXW1Oeqoo8zUqVNbX6euvfHJJ5+YQw45xJx33nnmf//3f82aNWvMk08+ad55553WY6hr\\\n",
       "b1x99dWmZ8+e5tFHHzVr1qwx//3f/232228/M3fu3NZjqOvMPPbYY2bGjBnmgQceMJLM4sWLY36f\\\n",
       "Sr1OmjTJ9OrVyyxdutS89NJLpqamxhx99NHmyy+/zPPZuIMOoGVOOOEEM2nSpJjXDj/8cHPppZf6\\\n",
       "VKJg2rJli5Fkli9fbowxpqWlxZSXl5trr7229ZjPP//clJaWmttuu82vYjpt+/btpl+/fmbp0qVm\\\n",
       "2LBhrR1A6to706dPNyeffHLC31PX3jnjjDPMD3/4w5jX6urqzDnnnGOMoa69sm8HMJV6/fTTT02n\\\n",
       "Tp3Mvffe23rMxo0bTYcOHcySJUvyVnbXEAK2yJ49e7Rq1SqNHj065vXRo0dr5cqVPpUqmLZt2yZJ\\\n",
       "6tGjhyRpzZo12rx5c0zdFxYWatiwYdR9hi688EKdccYZGjlyZMzr1LV3Hn74YQ0aNEjf/va3ddBB\\\n",
       "B+nYY4/VHXfc0fp76to7J598sp566im9/fbbkqS//vWveuaZZ3T66adLoq5zJZV6XbVqlb744ouY\\\n",
       "YyoqKjRw4EDqvh0d/S4AvvbRRx+publZZWVlMa+XlZVp8+bNPpUqeIwxuvjii3XyySdr4MCBktRa\\\n",
       "v/Hq/h//+Efey+i6e++9Vy+99JJeeOGFNr+jrr3z3nvv6dZbb9XFF1+syy+/XM8//7x+8pOfqLCw\\\n",
       "UOeeey517aHp06dr27ZtOvzww1VQUKDm5mZdc801GjdunCTada6kUq+bN29W586d1b179zbH8OxM\\\n",
       "jA6ghSKRSMx/G2PavIbMXXTRRfrb3/6mZ555ps3vqPvsrV+/XlOnTtUTTzyhLl26JDyOus5eS0uL\\\n",
       "Bg0apFmzZkmSjj32WL322mu69dZbde6557YeR11n77777tM999yjhQsX6ogjjtArr7yi+vp6VVRU\\\n",
       "aMKECa3HUde5kUm9UvftIwRskQMOOEAFBQVt/sWyZcuWNv/6QWamTJmihx9+WMuWLVNlZWXr6+Xl\\\n",
       "5ZJE3Xtg1apV2rJli4477jh17NhRHTt21PLly/Vf//Vf6tixY2t9UtfZO/jgg/WNb3wj5rUBAwZo\\\n",
       "3bp1kmjXXvr3f/93XXrppfre976nI488Ut///vc1bdo0zZ49WxJ1nSup1Gt5ebn27NmjrVu3JjwG\\\n",
       "bdEBtEjnzp113HHHaenSpTGvL126VEOGDPGpVMFgjNFFF12khoYG/fnPf1afPn1ift+nTx+Vl5fH\\\n",
       "1P2ePXu0fPly6j5NI0aM0OrVq/XKK6+0/gwaNEhnn322XnnlFfXt25e69shJJ53UZjmjt99+W4cc\\\n",
       "cogk2rWXdu7cqQ4dYh+ZBQUFrcvAUNe5kUq9HnfccerUqVPMMZs2bdKrr75K3bfHt+kniCu6DMxv\\\n",
       "f/tb8/rrr5v6+nrTrVs3s3btWr+L5rQf//jHprS01DQ2NppNmza1/uzcubP1mGuvvdaUlpaahoYG\\\n",
       "s3r1ajNu3DiWcPDI3rOAjaGuvfL888+bjh07mmuuucb8/e9/N3/4wx9M165dzT333NN6DHXtjQkT\\\n",
       "JphevXq1LgPT0NBgDjjgAHPJJZe0HkNdZ2b79u3m5ZdfNi+//LKRZG644Qbz8ssvty5/lkq9Tpo0\\\n",
       "yVRWVponn3zSvPTSS+af//mfWQYmCTqAFrrlllvMIYccYjp37my++c1vti5VgsxJivtz5513th7T\\\n",
       "0tJirrjiClNeXm4KCwvNKaecYlavXu1foQNk3w4gde2dRx55xAwcONAUFhaaww8/3Nx+++0xv6eu\\\n",
       "vdHU1GSmTp1qevfubbp06WL69u1rZsyYYXbv3t16DHWdmWXLlsX9fp4wYYIxJrV63bVrl7noootM\\\n",
       "jx49TFFRkRkzZoxZt26dD2fjjogxxvgz9ggAAAA/kAMIAAAQMnQAAQAAQoYOIAAAQMjQAQQAAAgZ\\\n",
       "OoAAAAAhQwcQAAAgZOgAAgAAhAwdQAAAgJChAwgAABAydAABAABChg4gAABAyNABBAAACBk6gAAA\\\n",
       "ACFDBxAAACBk6AACAACEDB1AAACAkKEDCAAAEDJ0AAEAAEKGDiAAAEDI0AEEAAAIGTqAAAAAIUMH\\\n",
       "EAAAIGToAAIAAIQMHUAAAICQoQMIAAAQMnQAAQAAQoYOIAAAQMjQAQQAAAgZOoAAAAAhQwcQAAAg\\\n",
       "ZOgAAgAAhMz/B+2RGq47XolVAAAAAElFTkSuQmCC\\\n",
       "\"\n",
       "\n",
       "\n",
       "    /* set a timeout to make sure all the above elements are created before\n",
       "       the object is initialized. */\n",
       "    setTimeout(function() {\n",
       "        anim9f8ef744d7ae49c1bb25688c6c5b7e4a = new Animation(frames, img_id, slider_id, 200.0,\n",
       "                                 loop_select_id);\n",
       "    }, 0);\n",
       "  })()\n",
       "</script>\n"
      ],
      "text/plain": [
       "<matplotlib.animation.FuncAnimation at 0x16caad370>"
      ]
     },
     "execution_count": 163,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = most_clustered_time(robots)\n",
    "animate_robots(robots, [t])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6a4794b4-1d3e-4d82-b886-4416ef5b6453",
   "metadata": {},
   "source": [
    "**It worked!** \n",
    "\n",
    "(At first I had a **bug**: the Christmas tree was upside down, because my Y-axis was upside down. So I added the `yaxis.set_inverted` call to `animate_robots`.)\n",
    "\n",
    "Although there was a human in the loop to verify the output, I can make this official with this call to `answer`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "id": "75434bc8-35ae-4d8b-b747-01d773472541",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 14.2:  1.802 seconds, answer 6876              ok"
      ]
     },
     "execution_count": 165,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(14.2, 6876, lambda:\n",
    "       most_clustered_time(robots, range(7000)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08cae29b-9b07-4e8d-b2d1-f3798f6c7cd0",
   "metadata": {},
   "source": [
    "# [Day 15](https://adventofcode.com/2024/day/15): Warehouse Woes\n",
    "\n",
    "Today's input is in two sections: the first section is a grid map describing a warehouse with walls (`#`) and boxes (`O`) and a single robot (`@`). The second part is a set of instructions for how the robot moves (arrows). I'll parse the two sections as paragraphs, then parse each paragraph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "id": "20be45ec-f6fc-472c-9b49-872b7334528c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 71 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "##################################################\n",
      "#..OO..O.O....O...O..O...O.......O...OO##....O.OO#\n",
      "#O.#..#OOO#..O..OO...O.O.....OO..O#O#.OOO.....#..#\n",
      "#.....O.......OO.#OO....#O.OO.O..OO.O.O.O..##....#\n",
      "#.O....O...O#...#...OO..#..O........#O..#..O..O..#\n",
      "#O....O...O.O..OO..OO..#OO.#OO.O......##..O..O...#\n",
      "#..O.##..#O...O...#.#.O.O..O.#......O..#.#...O...#\n",
      "#O.O.........O..O........OO....OO......O.....O#..#\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 2 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "##################################################\n",
      "#..OO..O.O....O...O..O...O.......O...OO##.... ...\n",
      ">><^v><>^v<<vv<>vv><v><<^^>>>>^^><>^<^^vvv>>><><>v^^^^<<^<^><>>>v><><vv^v^<>>>^>><>v>v>^v>>v>>>v ...\n"
     ]
    }
   ],
   "source": [
    "warehouse_woes = parse(15, sections=paragraphs)\n",
    "warehouse = Grid(parse(warehouse_woes[0]))\n",
    "arrows    = cat(parse(warehouse_woes[1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a4aed93-5205-4946-b04c-637f3b095e4b",
   "metadata": {},
   "source": [
    "### Part 1: What is the sum of all boxes' GPS coordinates after moving?\n",
    "\n",
    "The robot attempts to follow each instruction arrow (for example, moving East when the arrow is `>`). The robot is strong enough to push a line of any number of boxes sitting in front of it; that's its job. However, if a push is blocked by a wall, then neither the robot nor any boxes will move.\n",
    "\n",
    "The **GPS coordinate** of a box at (*x*, *y*) is defined to be *x* + 100*y*.\n",
    "\n",
    "I'll implement `obey_arrows` to make the arrow moves on a copy of the warehouse. For each arrow the function finds all the things that might move (the robot and any boxes) with `moveables`; then `make_movement` checks if they would bump into a wall, and if not, they all move."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 169,
   "id": "248d51c0-424e-4bbb-bbf4-37cdc18313e1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def gps_coordinate(box: Point) -> int: return X_(box) + 100 * Y_(box)\n",
    "\n",
    "def obey_arrows(warehouse: Grid, arrows: str) -> Grid:\n",
    "    \"\"\"Return a grid in which the robot has followed `arrows`, pushing boxes around.\"\"\"\n",
    "    grid = warehouse.copy()\n",
    "    robot_pos = the(grid.findall('@'))\n",
    "    for arrow in arrows:\n",
    "        dir = arrow_direction[arrow]\n",
    "        robot_and_boxes = moveables(grid, robot_pos, dir)\n",
    "        if make_movement(grid, robot_and_boxes, dir):\n",
    "            robot_pos = add(robot_pos, dir)\n",
    "    return grid\n",
    "\n",
    "def all_box_positions(grid) -> List[Point]: return grid.findall('O')\n",
    "\n",
    "def moveables(grid, start: Point, dir: Vector) -> List[Point]:\n",
    "    \"\"\"The positions of moveable things (the robot and maybe boxes) going in direction `dir` from the `start`.\"\"\"\n",
    "    def moveable(pos): return grid[pos] in ('@', 'O')\n",
    "    return list(takewhile(moveable, grid.follow_line(start, dir)))\n",
    "\n",
    "def make_movement(grid, to_move: List[Point], dir: Vector) -> bool:\n",
    "    \"\"\"Try to move the objects in the `to_move` positions in direction `dir`; return True if they move.\"\"\"\n",
    "    def destination(p): return add(p, dir) # Where we are trying to move `p` to\n",
    "    if grid[destination(to_move[-1])] == '#':\n",
    "        return False\n",
    "    else:\n",
    "        for p in reversed(to_move): # Reverse order so they don't step on each other\n",
    "            grid[destination(p)] = grid[p]\n",
    "            grid[p] = '.'\n",
    "        return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 170,
   "id": "52e93218-6ac2-4cf7-aced-f4f3a3df77b5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 15.1:   .026 seconds, answer 1563092           ok"
      ]
     },
     "execution_count": 170,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(15.1, 1563092, lambda:\n",
    "       sum(map(gps_coordinate, all_box_positions(obey_arrows(warehouse, arrows)))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "84dcd7fd-0f4a-4377-b61e-22bd5a0a51a9",
   "metadata": {},
   "source": [
    "### Part 2: What is the sum of all boxes' final GPS coordinates on the double-wide grid?\n",
    "\n",
    "In Part 2, there is another warehouse that is similar to the first, but twice as wide. Each position in the original warehouse is replaced by *two* copies of the contents, except that the robot is replaced by `@.` and a box, `O`, is replaced by `[]`, indicating the two halves of a double-wide box. The rules for movement and pushing are the same, except that when the robot is moving North or South and is pushing a box, that box, since it is two positions wide, can push *two* boxes if they are lined up right. (Presumably, those two boxes could then push three boxes in the next row, and so on, although the puzzle description did not explicitly specify that). Finally, the GPS coordinates are taken for the `[` part of the box. Here's what it looks like before and after the robot moves \"^\":\n",
    "\n",
    "        ##############        ##############\n",
    "        ##......##..##        ##......##..##\n",
    "        ##..........##        ##...[][]...##\n",
    "        ##...[][]...##        ##....[]....##\n",
    "        ##....[]....##        ##.....@....##\n",
    "        ##.....@....##        ##..........##\n",
    "        ##############        ##############\n",
    "\n",
    "So this is mostly the same as Part 1, but the criteria of what to move is different. Here are the changes I'll make:\n",
    "- I'll need to make the double-wide grid, by applying `doublewide` to the original text to get `warehouse2`.\n",
    "- I'll redefine `make_movement` to check for a wall in front of *any* of the boxes, not just the last one, and to move them all in one `update`, rather than one at a time.\n",
    "- I'll redefine `moveables` to deal with either regular or double-wide boxes (but not both in one maze).\n",
    "\n",
    "The redefinitions are backwards-comnpatible, which I'll demonstrate by re-running Part 1 before running Part 2:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 172,
   "id": "2d9afbc1-75b2-479d-81fc-fbab69d25753",
   "metadata": {},
   "outputs": [],
   "source": [
    "def doublewide(text: str) -> str:\n",
    "    \"\"\"Make the grid (described in text) twice as wide.\"\"\"\n",
    "    return text.replace('#', '##').replace('O', '[]').replace('.', '..').replace('@', '@.')\n",
    "    \n",
    "warehouse2 = Grid(parse(doublewide(warehouse_woes[0])))\n",
    "\n",
    "def make_movement(grid, to_move: Collection[Point], dir: Vector) -> bool:\n",
    "    \"\"\"Try to move the objects in the `to_move` positions in direction `dir`; return True if they move.\"\"\"\n",
    "    def destination(p): return add(p, dir) # Where we are trying to move `p` to\n",
    "    if any(grid[destination(p)] == '#' for p in to_move):\n",
    "        return False\n",
    "    else:\n",
    "        updates = {destination(p): grid[p] for p in to_move}\n",
    "        grid.update({p: '.' for p in to_move})\n",
    "        grid.update(updates)\n",
    "        return True\n",
    "\n",
    "def moveables(grid, start_pos, dir) -> Set[Point]:\n",
    "    \"\"\"The positions of moveable things (robot and maybe boxes) going in direction from the start.\"\"\" \n",
    "    ahead = add(start_pos, dir)\n",
    "    if dir in (East, West) or grid[ahead] == 'O': # Single line push\n",
    "        def moveable(pos): return grid[pos] in ('@', 'O', '[', ']')\n",
    "        return set(takewhile(moveable, grid.follow_line(start_pos, dir)))\n",
    "    else: # Potential non-linear push\n",
    "        results = {start_pos}\n",
    "        if grid[ahead] in ('[', ']'): results |= moveables(grid, ahead, dir) \n",
    "        if grid[ahead] == '[':        results |= moveables(grid, add(ahead, East), dir)\n",
    "        if grid[ahead] == ']':        results |= moveables(grid, add(ahead, West), dir)\n",
    "        return results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 173,
   "id": "7af49bbf-dd10-4221-9096-6f548dec44c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 15.1:   .028 seconds, answer 1563092           ok"
      ]
     },
     "execution_count": 173,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(15.1, 1563092, lambda:\n",
    "       sum(map(gps_coordinate, obey_arrows(warehouse, arrows).findall('O'))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 174,
   "id": "99246602-a51e-41aa-a7e9-7cdbc8d449ca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 15.2:   .041 seconds, answer 1582688           ok"
      ]
     },
     "execution_count": 174,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(15.2, 1582688, lambda:\n",
    "       sum(map(gps_coordinate, obey_arrows(warehouse2, arrows).findall('['))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4361f8c3-1d15-441e-9a41-b1ea20707651",
   "metadata": {},
   "source": [
    "I had a frustrating time **debugging** this one; this was by far my worst performance on this year's puizzles so far. First I had a silly typo in `moveables`; I was able to fix it after looking at the results on the smaller test puzzle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 176,
   "id": "47c99f0f-ab65-4ae1-a308-42668feacdd5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "##############\n",
      "##...[].##..##\n",
      "##...@.[]...##\n",
      "##....[]....##\n",
      "##..........##\n",
      "##..........##\n",
      "##############\n"
     ]
    }
   ],
   "source": [
    "xwarehouse = Grid(parse(doublewide(\"\"\"\\\n",
    "#######\n",
    "#...#.#\n",
    "#.....#\n",
    "#..OO@#\n",
    "#..O..#\n",
    "#.....#\n",
    "#######\"\"\")))\n",
    "\n",
    "xarrows = \"<vv<<^^<<^^\"\n",
    "\n",
    "obey_arrows(xwarehouse, xarrows).print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30a6d933-8969-427d-b82f-c5fb95d10164",
   "metadata": {},
   "source": [
    "Once I found my first bug and got this correct final grid, I couldn't see what I had done wrong. It turns out that I had all the movements correct, but my **bug** was summing the GPS coordinates of *both* sides of the boxes when I should have been using just the *left* sides. Lesson learned: read the instructions carefully!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9b4132fb-6365-4aed-bd11-aedf560933e1",
   "metadata": {},
   "source": [
    "# [Day 16](https://adventofcode.com/2024/day/16): Reindeer Maze\n",
    "\n",
    "Today's input is yet another 2D grid, this one a maze that reindeer race through:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "id": "03255fd5-95d9-4a90-b1bb-abdf6bbf1d85",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 141 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "################################################################################################ ...\n",
      "#.................#.................#.............#.......#...................#.......#......... ...\n",
      "#.#.###############.#####.#####.###.#.#########.###.#.###.#.#################.#.#####.#.#.#####. ...\n",
      "#.#.#.....#.........#...#.#...#.#.#.#.........#.....#.#...#.....#...#.........#.#.......#.#..... ...\n",
      "###.#.###.#.#########.#.###.#.#.#.#.###.#############.#.###.###.#.###.#########.#.#####.#.###### ...\n",
      "#...#...#...#...#...#.#.#...#...#.....#.#...#.........#...#...#.#.#...#.......#.#...#.....#..... ...\n",
      "#.#####.#####.###.#.#.#.#.###.#######.###.#.#.###########.#####.#.#.###.#####.#.###.#.#.###.#### ...\n",
      "#.......#...#...#.#.#.#...#...#...#.................................#...#...#...#...#.#.#.....#. ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "maze = Grid(parse(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74e37bd1-f994-4e98-b6ed-8469ca7f3805",
   "metadata": {},
   "source": [
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/665/139/461/284/421/small/fbe45a948b982c5a.jpg\" width=400>\n",
    "\n",
    "\n",
    "\n",
    "### Part 1: What is the lowest score a Reindeer could possibly get?\n",
    "\n",
    "The race through the maze starts at the `S` position and ends at the `E`.  A reindeer is allowed to take a step forward (as long as there isn't a `#` wall there) or to turn 90 degrees right or left. The reindeer is initially facing East.  The **score** for a path is one point for every forward step and 1000 points for every turn.\n",
    "\n",
    "We're asked to find the path with the minimum score. My [AdventUtils](AdventUtils.ipynb) notebook already contains an `A_star_search` function for finding least-cost paths, and a `GridProblem` class. By default, a `GridProblem` counts one point for a move in any direction, so we'll have to create a subclass, `MazeSearchProblem`. This is straightforward but a bit tedious; I had a **bug** where I accepted the default `is_goal` and `h` methods; that doesn't work because they assume the state is just a position; but for this problem the state contains both the position and the facing direction. Another **bug** was that I left out the `goal=end` in the call to `MazeSearchProblem`. I thought I wouldn't need it because I wrote an `is_goal` method, but the `goal` is needed in the `h` (heuristic estimate) method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 181,
   "id": "e6e4bfba-0170-436a-961b-d4749f2cd66e",
   "metadata": {},
   "outputs": [],
   "source": [
    "State = namedtuple('State', 'pos, facing')\n",
    "\n",
    "def reindeer_path(maze) -> Node:\n",
    "    \"\"\"The lowest-cost path through the maze.\"\"\"\n",
    "    start, end = the(maze.findall('S')), the(maze.findall('E'))\n",
    "    problem = MazeSearchProblem(grid=maze, initial=State(start, East), goal=end)\n",
    "    return A_star_search(problem)\n",
    "\n",
    "class MazeSearchProblem(GridProblem):\n",
    "    \"\"\"A GridProblem where a turn costs 1000 points, a step ahead 1.\"\"\"\n",
    "    \n",
    "    def actions(self, state):\n",
    "        ahead = add(state.pos, state.facing)\n",
    "        return ['L', 'R'] + ([ahead] if self.grid[ahead] != '#' else [])\n",
    "                \n",
    "    def result(self, state, action) -> State:\n",
    "        return (State(state.pos, make_turn(state.facing, action))   if action in ('L', 'R') else\n",
    "                State(add(state.pos, state.facing), state.facing))\n",
    "            \n",
    "    def action_cost(self, s1, action, s2) -> int: return 1000 if action in ('L', 'R') else 1\n",
    "\n",
    "    def is_goal(self, state) -> bool: return self.grid[state.pos] == 'E'\n",
    "\n",
    "    def h(self, node) -> int: return taxi_distance(node.state.pos, self.goal)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 182,
   "id": "4974c14c-86da-4b86-a55c-6ae8781df207",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 16.1:   .146 seconds, answer 103512            ok"
      ]
     },
     "execution_count": 182,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(16.1, 103512, lambda:\n",
    "       reindeer_path(maze).path_cost)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "030e5786-cd2a-405f-b4d4-460cefab7e32",
   "metadata": {},
   "source": [
    "### Part 2: How many tiles are part of at least one of the best paths through the maze?\n",
    "\n",
    "In Part 2 we're asked to find the total number of positions that are part of *any* best path from start to end. I'll write a new version of `best_first_search` to return all the paths that have the same cost as the best path. I thought this would be easy, but I had **another bug** where I forgot to change the `<` to a `<=` in the fourth-to-last line of `all_paths_best_first_search`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 184,
   "id": "692abfea-f9c8-477c-8369-386cdd2a7606",
   "metadata": {},
   "outputs": [],
   "source": [
    "def reindeer_best_positions(maze) -> Node:\n",
    "    \"\"\"All the positions on any best path from start to end.\"\"\"\n",
    "    start, end = the(maze.findall('S')), the(maze.findall('E'))\n",
    "    problem = MazeSearchProblem(grid=maze, initial=State(start, East), goal=end)\n",
    "    paths = list(all_paths_best_first_search(problem, f=lambda n: n.path_cost + problem.h(n)))\n",
    "    return union({state.pos for state in path_states(path)} for path in paths)\n",
    "\n",
    "def all_paths_best_first_search(problem, f) -> List[Node]:\n",
    "    \"Search nodes with minimum f(node) value first, return all paths with minimum cost.\"\n",
    "    node = Node(problem.initial)\n",
    "    frontier = PriorityQueue([node], key=f)\n",
    "    reached = {problem.initial: node}\n",
    "    while frontier:\n",
    "        node = frontier.pop()\n",
    "        if problem.is_goal(node.state):\n",
    "            return [node] + [path for (cost, path) in frontier.items\n",
    "                             if cost == node.path_cost and problem.is_goal(path.state)]\n",
    "        for child in expand(problem, node):\n",
    "            s = child.state\n",
    "            if s not in reached or child.path_cost <= reached[s].path_cost:\n",
    "                reached[s] = child\n",
    "                frontier.add(child)\n",
    "    return []"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 185,
   "id": "ea9bf9f3-0e6b-4949-a641-6b3db2fd9d32",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 16.2:   .837 seconds, answer 554               ok"
      ]
     },
     "execution_count": 185,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(16.2, 554, lambda:\n",
    "    len(reindeer_best_positions(maze)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "91607c18-56c3-4432-8da8-cfe570887bc0",
   "metadata": {},
   "source": [
    "# [Day 17](https://adventofcode.com/2024/day/17): Chronospatial Computer\n",
    "\n",
    "Today we have to help debug a faulty computer. This particular computer has three registers, A, B, and C, and a program consisting of a sequence of octal digits. The input is a description of the state of the computer: the register values and the stored program. Since the format is the same,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 187,
   "id": "50fd3cb8-0a6f-4edd-b5cb-f7b1e6f9d987",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 5 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Register A: 52042868\n",
      "Register B: 0\n",
      "Register C: 0\n",
      "\n",
      "Program: 2,4,1,7,7,5,0,3,4,4,1,7,5,5,3,0\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 3 ints, 1 list:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "52042868\n",
      "0\n",
      "0\n",
      "[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Computer(A=52042868, B=0, C=0, program=[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0])"
      ]
     },
     "execution_count": 187,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Computer = namedtuple('Computer', 'A, B, C, program')\n",
    "    \n",
    "def parse_computer(text: str) -> Computer:\n",
    "    \"\"\"Parse the text, extracting values for registers and program.\"\"\"\n",
    "    A, B, C, *program = ints(text)\n",
    "    return Computer(A, B, C, program)\n",
    "\n",
    "computer = parse(17, parse_computer, sections=None) # Just find all the integers\n",
    "computer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 188,
   "id": "c23b8a44-e352-4a30-abe5-3c939ffc743c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Computer(A=52042868, B=0, C=0, program=[2, 4, 1, 7, 7, 5, 0, 3, 4, 4, 1, 7, 5, 5, 3, 0])"
      ]
     },
     "execution_count": 188,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "computer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "031ec910-e249-487b-ae95-b98abae3b9cf",
   "metadata": {},
   "source": [
    "### Part 1: Run the Program. What do you get if you use commas to join the output values?\n",
    "\n",
    "Now we have to run the program. The computer has eight opcodes; each opcode operates on the following value in memory; some instructions take the operand literally, and some compute a **combo value** from it.  The combo value is the same as the literal value, except that values 4, 5, and  6 refer to registers A, B, and C, respectively. Opcode 5 outputs (yields) the last octal digit of the combo value. There is a program counter (pc) that increments by 2 on each instruction (to skip over the operand) unless there is a branch instuction (opcode 3). See the [day's description](https://adventofcode.com/2024/day/17) for details on how the opcodes work."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 190,
   "id": "d98f88cc-c435-43fc-bcb5-52e6dd70fdb1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def run_program(computer) -> Iterable[int]:\n",
    "    \"\"\"Run the program on the computer, yielding each output.\"\"\"\n",
    "    A, B, C, program = computer\n",
    "    pc = 0\n",
    "    while pc < len(program):\n",
    "        op, val = program[pc:pc+2]\n",
    "        pc += 2\n",
    "        combo = (A if val == 4 else B if val == 5 else C if val == 6 else val)\n",
    "        match op:\n",
    "            case 0: A = A // (2 ** combo)\n",
    "            case 6: B = A // (2 ** combo)\n",
    "            case 7: C = A // (2 ** combo)\n",
    "            case 1: B = B ^ val\n",
    "            case 4: B = B ^ C\n",
    "            case 2: B = combo % 8\n",
    "            case 5: yield combo % 8\n",
    "            case 3: \n",
    "                if A: pc = val"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6348d561-9ac9-437c-8bcd-6fbd91d1ebf5",
   "metadata": {},
   "source": [
    "With my `run_program` function, the answer for Part 1 is easy:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 192,
   "id": "860f24e5-92ad-4361-8920-102ebc573598",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 17.1:   .000 seconds, answer 2,1,0,1,7,2,5,0,3 ok"
      ]
     },
     "execution_count": 192,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(17.1, '2,1,0,1,7,2,5,0,3', lambda:\n",
    "       cat(run_program(computer), ','))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3248e42-ab8e-4fdb-8e19-439766275c37",
   "metadata": {},
   "source": [
    "### Part 2: What is the lowest positive initial value for register A that causes the program to output a copy of itself?\n",
    "\n",
    "In Part 2, we find that register A has been corrupted, and we need to restore it to the value that will make the program output a copy of itself (a [Quine](https://en.wikipedia.org/wiki/Quine_%28computing%29)). I was afraid of this! AoC always has a puzzle where you have to write an interpreter for a program in some obscure language, but then in Part 2 you have to actually *understand* what the program is doing; you can't use brute force. (I tried brute force up to A=10,000,000 with no luck.)\n",
    "\n",
    "To try to understand my program, here it is in pseudocode:\n",
    "\n",
    "    top: B = A % 8        # 2, 4\n",
    "         B = B ^ 7        # 1, 7\n",
    "         C = A / 2 ** B   # 7, 5\n",
    "         A = A / 2 ** 3   # 0, 3\n",
    "         B = B ^ C        # 4, 4\n",
    "         B = B ^ 7        # 1, 7\n",
    "         output B         # 5, 5\n",
    "         if A: goto top   # 3, 0\n",
    "\n",
    "I can summarize that as:\n",
    "\n",
    "    top: B and C are defined in terms of the last octal digit of A, and prior value of B\n",
    "         A is shifted to eliminate the last octal digit\n",
    "         output B       \n",
    "         if A: goto top \n",
    "\n",
    "So I realized that one octal digit of `A` is eliminated on each pass through the loop, and when `A` hits zero, we exit. Each pass outputs one octal digit, so `A` in octal has to be the same number of digits as my program; 16 octal digits is somewhere in the hundred trillion range. Good thing I gave up on brute force. \n",
    "\n",
    "I started playing around and came up with this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 194,
   "id": "bb745303-dd20-486f-bbdd-7ae77f995c2c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def run(computer=computer, **registers) -> List[int]: \n",
    "    \"\"\"Run the program with registers set as keywords.\"\"\"\n",
    "    return list(run_program(computer._replace(**registers)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 195,
   "id": "36d89d9a-c8fc-41be-820b-cb13e40793c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0]"
      ]
     },
     "execution_count": 195,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run(A=0o7)   # match the last digit of program"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 196,
   "id": "892fef38-5f9b-4370-a242-f7a10df5487b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[3, 0]"
      ]
     },
     "execution_count": 196,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run(A=0o72)   # match the last two digits of program"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 197,
   "id": "b3d11d5e-30c2-419f-bc11-3f26fbdddfbb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 3, 0]"
      ]
     },
     "execution_count": 197,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run(A=0o726)   # match the last three digits of program"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 198,
   "id": "9ffcefa7-714f-416f-b6c7-8a9ad6d65380",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 5, 3, 0]"
      ]
     },
     "execution_count": 198,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run(A=0o7266)   # match the last four digits of program"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f40f775f-bb9d-459c-80c3-ac09b6b42904",
   "metadata": {},
   "source": [
    "That is, I can build up the right value for `A` to generate a Quine program as follows:\n",
    "\n",
    "- I'm going to keep a **set** of candidate partial values for `A` as the set `As`.\n",
    "- The set starts with no digits, so just `{0}`.\n",
    "- On each iteration I try appending each octal digit to each element of the set `As` (by multplying by 8 and adding the digit).\n",
    "- I keep the candidate `A` values whose output from the run matches the tail of the program's output.\n",
    "    - On each iteration we insist on matching one more octal digit of the tail of the program \n",
    "- Iterate this for each digit in the program and return the set of `A` values that reproduce the whole program.\n",
    "\n",
    "All of the resulting `A` values will be Quines, but the puzzle asks us to find just the minimum of the set."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "id": "2d244126-bcf4-4ef6-b9e8-1c9f4c682f07",
   "metadata": {},
   "outputs": [],
   "source": [
    "def quine(computer) -> Set[int]:\n",
    "    \"\"\"Find the values of register `A` that cause the output of the run to match the program.\"\"\"\n",
    "    As = {0} # Set of candidate partial values for register A\n",
    "    for place in reversed(range(len(computer.program))):\n",
    "        tail = computer.program[place:]\n",
    "        candidates = {(A * 8) + d for A in As for d in range(8)}\n",
    "        As = {A for A in candidates if run(A=A) == tail}\n",
    "    return As"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 201,
   "id": "82e2e6af-ec1b-4f37-a975-3e39152ebe3a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 17.2:   .004 seconds, answer 267265166222235   ok"
      ]
     },
     "execution_count": 201,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(17.2, 267265166222235, \n",
    "       lambda: min(quine(computer)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7f9e900-45be-401f-a6f2-a1d7b751fae6",
   "metadata": {},
   "source": [
    "# [Day 18](https://adventofcode.com/2024/day/18): RAM Run\n",
    "\n",
    "In today's narrative, we're inside a computer, on a 2D memory board, and bytes are falling down, at specified (x, y) positions, as given in our input:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 203,
   "id": "d14e1966-2feb-4553-9a0a-12595ef4f7d7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 3450 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "40,65\n",
      "17,1\n",
      "34,45\n",
      "31,51\n",
      "29,43\n",
      "25,9\n",
      "14,27\n",
      "5,29\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 3450 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "(40, 65)\n",
      "(17, 1)\n",
      "(34, 45)\n",
      "(31, 51)\n",
      "(29, 43)\n",
      "(25, 9)\n",
      "(14, 27)\n",
      "(5, 29)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "falling_bytes = parse(18, ints)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1229cec7-a456-4dd6-a668-8a00591c63f7",
   "metadata": {},
   "source": [
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/675/173/635/175/528/small/844f7f437bf670c7.jpg\" width=400>\n",
    "\n",
    "### Part 1: What is the minimum number of steps needed to reach the exit?\n",
    "\n",
    "When a byte falls it creates a barrier. Our task is to find a path that avoids the barriers, from the start in the upper left to the exit in the lower right of a 71 x 71 grid that is the memory board. \n",
    "\n",
    "This is another search puzzle, like the maze in Day 16, but without the complications (e.g. costs for turning right or left), so I can use my `GridProblem` class from [AdventUtils](AdventUtils.ipynb) without alteration. The puzzle description for today says that we should first consider just the first kilobyte (1024 falling bytes), and I was worried that if I just hand those points to my `Grid` class, it wouldn't cover the whole 71 x 71 grid. Therefore, I created a grid with empty spaces, and then updated with the falling bytes. The function `memory_path` returns a path, and we can then ask for its length to get the answer."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "id": "83af4751-38c9-4830-a2fa-78515b59bc97",
   "metadata": {},
   "outputs": [],
   "source": [
    "def memory_path(falling_bytes: Tuple[Point], width=71, height=71) -> Grid:\n",
    "    \"\"\"Make a Grid of the given size with the points as obstacles, and find a path.\"\"\"\n",
    "    grid = Grid(['.' * width] * height)\n",
    "    grid.update({p: '#' for p in falling_bytes})\n",
    "    problem = GridProblem(grid=grid, initial=(0, 0), goal=(width - 1, height - 1))\n",
    "    return A_star_search(problem)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 206,
   "id": "29da25e2-f3c2-43e3-8769-1d4fcecb807b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 18.1:   .014 seconds, answer 344               ok"
      ]
     },
     "execution_count": 206,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(18.1, 344, lambda:\n",
    "       len(memory_path(falling_bytes[:1024])))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "792bc31e-964d-47fe-a09b-6a95724e641e",
   "metadata": {},
   "source": [
    "### Part 2: What are the coordinates of the first byte that will prevent the exit from being reachable from your starting position?\n",
    "\n",
    "After 1024 bytes fall there is a path from start to exit, but as more bytes fall we might have to switch to a different path, and eventually there will be no path. We're asked for the `(x,y)` position of the first falling byte that blocks off the last possible path. I can think of two ways to handle this:\n",
    "1) Add falling bytes one at a time and repeat the A-star search each time. **Slow!**\n",
    "2) Add falling bytes in **binary search** fashion: We know adding no bytes is **good** for getting a path and adding all of them is **bad**; try half way and then update **good** or **bad** depending on whether we found a path. Repeat until **good** is one more than **bad**; that's the answer.  **Fast!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 208,
   "id": "4c0a8dcb-c3af-45e7-9273-8776e8c3ea1d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def memory_blocker(falling_bytes, good=1024) -> Point:\n",
    "    \"\"\"Which falling byte is the first to block a path to the exit? Do binary search.\"\"\"\n",
    "    # Here `good` and `bad` are the stop values of a slice, not an index,\n",
    "    # so the final answer is falling_bytes[bad - 1], not falling_bytes[bad]\n",
    "    bad  = len(falling_bytes) \n",
    "    while bad != good + 1:\n",
    "        mid = (good + bad) // 2\n",
    "        if memory_path(falling_bytes[:mid]) == search_failure:\n",
    "            bad = mid\n",
    "        else:\n",
    "            good = mid\n",
    "    return falling_bytes[bad - 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 209,
   "id": "22371144-5d51-440a-918f-a63de73b13ad",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 18.2:   .031 seconds, answer 46,18             ok"
      ]
     },
     "execution_count": 209,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(18.2, '46,18', lambda:\n",
    "       cat(memory_blocker(falling_bytes), ','))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "552f1c6e-052e-43d0-b13f-e8f66f274d63",
   "metadata": {},
   "source": [
    "I admit I initially had an off-by-one **bug** here. I was inconsistent on whether `bad` should be an **index** into the falling byte arrays, or the **stop** of a slice.\n",
    "\n",
    "I realize that for Part 1 I should have had separate functions for making the grid and solving it; then in Part 2 I could have incrementally modified the grid each time rather than creating a whole new Grid (and Problem). But it runs in under 1/10 second, so it is not worth changing it."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "702d6ea3-bcb1-4c90-8d67-9e686cd0155f",
   "metadata": {},
   "source": [
    "# [Day 19](https://adventofcode.com/2024/day/19): Linen Layout\n",
    "\n",
    "Today's input is in two sections, the first a list of towel patterns (with each letter of a word specifying a color), and the second a list of desired designs to be made by adjoining towel patterns.  For example, if the patterns include\n",
    "\n",
    "     a, dub, rub, ...\n",
    "\n",
    "and the desired design is\n",
    "\n",
    "     rubadubdub\n",
    "\n",
    "then it can be made from the patterns with\n",
    "\n",
    "     rub + a + dub + dub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 212,
   "id": "689df92b-92d7-44e6-8b4e-d67bf3f153df",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 402 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "rub, wugrr, gww, wgurb, urur, ggb, bw, uubbu, uw, uggru, gwwgrgb, wbbb, rgb, wuuur, bgruggug, ru ...\n",
      "\n",
      "rurgggubugbuwugbwgggwbwwwrbrbgwwwwuwuugrwbrbwgguwr\n",
      "ruurbrwgrurubwrurugubgurgruurwgugwgrwuwbrww\n",
      "gwbrwwruwubrwgubggggubwwrurugbbuuugwwburbw\n",
      "wwgwugrrrbwbgwburguwgbrgrwurugbbgubuuugbguur\n",
      "ubgbbrruwbgbrrgwwwwwrwgggggrwbgwuwgrwrbwbrg\n",
      "rurbbgrbwbggugrbwwbwrwuwuwbwwbwugwrubbww\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 2 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "('rub', 'wugrr', 'gww', 'wgurb', 'urur', 'ggb', 'bw', 'uubbu', 'uw', 'uggru', 'gwwgrgb', 'wbbb', ...\n",
      "('rurgggubugbuwugbwgggwbwwwrbrbgwwwwuwuugrwbrbwgguwr', 'ruurbrwgrurubwrurugubgurgruurwgugwgrwuwb ...\n"
     ]
    }
   ],
   "source": [
    "patterns, designs = parse(19, atoms, sections=paragraphs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "581ff31b-ec09-4ae5-84c7-3b3ffbbd9362",
   "metadata": {},
   "source": [
    "### Part 1: How many of the desired designs are possible?\n",
    "\n",
    "The task is to see how many of the desired designs can posibly be made by concatenating one or more of the patterns (with repetitions allowed). I can do this by checking if some pattern starts the design and recursively checking if the rest of the design is possible."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 214,
   "id": "e0b96545-5f60-4c8e-9a0f-c77608c19128",
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_possible_design(design, patterns=patterns) -> bool:\n",
    "    \"\"\"Is it possible to make `design` by concatenating some of the `patterns`?\"\"\"\n",
    "    return (design == '' \n",
    "            or any(design.startswith(p) and is_possible_design(design[len(p):], patterns) \n",
    "                   for p in patterns))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 215,
   "id": "3c3fba1b-d3e5-494e-aad0-42ca0566ae1f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 19.1:   .038 seconds, answer 242               ok"
      ]
     },
     "execution_count": 215,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(19.1, 242, lambda:\n",
    "        quantify(designs, is_possible_design))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7a03f27-c1af-4561-a887-ff4f9b7b0b51",
   "metadata": {},
   "source": [
    "### Part 2: What do you get if you add up the number of different ways you could make each design?\n",
    "\n",
    "For Part 2 we need to count all the ways that each design can be made. Since there can be an exponential number of ways for each design, I'm going to `cache` intermediate results. The number of ways is computed by considering each pattern that starts the design and recursively summing up the count of the number of ways for the rest of the design."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 217,
   "id": "77d4fae1-d506-4733-9bb2-467619012f97",
   "metadata": {},
   "outputs": [],
   "source": [
    "@cache\n",
    "def count_ways(design, patterns=patterns) -> int:\n",
    "    \"\"\"How many ways can the design be made from the patterns?\"\"\"\n",
    "    return (1 if design == '' else\n",
    "            sum(count_ways(design[len(p):], patterns)\n",
    "                for p in patterns if design.startswith(p)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 218,
   "id": "14116eca-0b0f-484a-a169-9726e4ac7fbf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 19.2:   .180 seconds, answer 595975512785325   ok"
      ]
     },
     "execution_count": 218,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(19.2, 595975512785325, lambda:\n",
    "       sum(map(count_ways, designs)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1199e79-bb09-4d68-89e6-b235c5f987c5",
   "metadata": {},
   "source": [
    "### Part 3: Exploration\n",
    "\n",
    "That was so easy that there is time to explore a bit more. First, here's a check that says a design is possible if and only if there is at least one way to make it: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 220,
   "id": "f992b197-be14-47dc-8678-10cc63a1afd7",
   "metadata": {},
   "outputs": [],
   "source": [
    "for d in designs:\n",
    "    assert is_possible_design(d) == (count_ways(d) >= 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a003849a-ae35-4c86-8d48-b954908d636b",
   "metadata": {},
   "source": [
    "Here is an alternative approach to Part 1 that turns out to be faster. It uses one big regular expression to match repetitions of the designs. We then check for a full-line match against each of the desired designs. Note that the `fullmatch` method in the `re` module looks for a full match of the input string, similar to `r\"^...$\"`. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 222,
   "id": "2437ae06-27e4-4840-ad51-65454ef0bf60",
   "metadata": {},
   "outputs": [],
   "source": [
    "def count_possible_designs(designs, patterns) -> int:\n",
    "    \"\"\"A count of all the `designs` that can be made by concatenating `patterns`.\"\"\"\n",
    "    regex = re.compile(\"(\" + \"|\".join(patterns) + \")+\")\n",
    "    return quantify(designs, regex.fullmatch)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 223,
   "id": "88e45604-ce45-478e-a1b8-66ead1d0e72e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 19.1:   .004 seconds, answer 242               ok"
      ]
     },
     "execution_count": 223,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(19.1, 242, lambda: \n",
    "       count_possible_designs(designs, patterns))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "efc9dc54-cdcc-40d5-85d5-b8ed8da61ba2",
   "metadata": {},
   "source": [
    "# [Day 20](https://adventofcode.com/2024/day/20): Race Condition\n",
    "\n",
    "Yet another puzzle with a grid, this one depicting a racetrack:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 225,
   "id": "156dcbf7-79ec-41a7-a9f2-397a827b9856",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 141 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "################################################################################################ ...\n",
      "#...#...#...........#...#...#...#...#.....#...###...#...###.........#...#...#.......#...#...#... ...\n",
      "#.#.#.#.#.#########.#.#.#.#.#.#.#.#.#.###.#.#.###.#.#.#.###.#######.#.#.#.#.#.#####.#.#.#.#.#.#. ...\n",
      "#.#...#.#...#.....#...#...#...#.#.#.#...#...#...#.#...#...#.......#...#...#.#.....#.#.#...#.#.#. ...\n",
      "#.#####.###.#.###.#############.#.#.###.#######.#.#######.#######.#########.#####.#.#.#####.#.#. ...\n",
      "#.#.....###...###.......#.......#.#.....#.......#.......#...#.....#...#.....#...#.#.#.....#...#. ...\n",
      "#.#.###################.#.#######.#######.#############.###.#.#####.#.#.#####.#.#.#.#####.#####. ...\n",
      "#.#.#...###...#...#.....#.......#.......#.###...#...###...#.#...#...#...###...#.#.#...###.....#. ...\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "racetrack = Grid(parse(20))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57918fd0-bb72-4c5e-8e1f-3bcf164a1d72",
   "metadata": {},
   "source": [
    "### Part 1: How many cheats would save you at least 100 picoseconds?\n",
    "\n",
    "We are told that the grid depicts a single path from start (`S`) to end (`E`). Each step (in one of the four cardinal directions) takes one picosecond. But you are allowed to **cheat** once during the race by going through a wall: you can take two steps where the first step is into a wall and the second is back onto the track. We are asked how many such cheats would save 100 picoseconds or more.\n",
    "\n",
    "This is an all-paths-to-the-goal puzzle, which should make you think [**Dijkstra's algorithm**](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). But the full Dijkstra's algorithm handles steps with different costs; in this problem all the steps have the same cost, so we can simplify: we don't need to worry about a second path to the goal costing less than the first path to the goal. We end up with an all-paths-to-the-goal [breadth-first search](https://en.wikipedia.org/wiki/Breadth-first_search) function that I will name `all_distances`. It returns a dict of `{start_point: distance_to_end_point}` for all start points. It works by maintaining a queue, `Q` of points to be considered, and one at a time popping a point off the queue, and for each neighbor that is not a wall, add the neighbor to the queue and record the distance to the neighbor as being one more than the distance to the point in the dict `distance_from`. Since we are told the grid is single-path, we don't have to worry about updating entries in `distance_from` for a second path to a point.\n",
    "\n",
    "Then my function `cheats` yields all `(start_position, end_position, time_saved)` tuples where the time saved is at least the given lower bound."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 227,
   "id": "4c4ef05c-b548-49f9-b092-847e9752e745",
   "metadata": {},
   "outputs": [],
   "source": [
    "def all_distances(grid, end: Point) -> Dict[Point, int]:\n",
    "    \"\"\"All-paths distances from each point on the grid to the end position: {(x, y): distance}.\"\"\"\n",
    "    distance_from = {end: 0}\n",
    "    Q = [end]\n",
    "    while Q:\n",
    "        p = Q.pop()\n",
    "        for p2 in grid.neighbors(p):\n",
    "            if grid[p2] != '#' and p2 not in distance_from:\n",
    "                Q.append(p2)\n",
    "                distance_from[p2] = distance_from[p] + 1\n",
    "    return distance_from\n",
    "\n",
    "def cheats(racetrack, minimum_savings=1) -> Iterable[Tuple[Point, Point, int]]:\n",
    "    \"\"\"All ways of cheating by taking one step onto a wall (at p2) and a second step back on track (at p3),\n",
    "    as long as they save at lease `minimum_savings` picoseconds\"\"\"\n",
    "    D = all_distances(racetrack, the(racetrack.findall('E'))) # A dict of {sposition: distance_to_E}\n",
    "    return ((p1, p3, t)\n",
    "            for p1 in D\n",
    "            for p2 in racetrack.neighbors(p1) if racetrack[p2] == '#'\n",
    "            for p3 in racetrack.neighbors(p2)\n",
    "            if  p3 in D and (t := D[p1] - D[p3] - 2) >= minimum_savings)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 228,
   "id": "1bbd8b72-c503-4384-aaea-a5bed45a4491",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 20.1:   .029 seconds, answer 1343              ok"
      ]
     },
     "execution_count": 228,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(20.1, 1343, lambda:\n",
    "       quantify(cheats(racetrack, 100)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f86c3a4-47e7-4731-8acf-9133b3e41838",
   "metadata": {},
   "source": [
    "At first I had a puzzling **bug**. I had a lot of confidence in my code, but AoC said I had the wrong answer. I addressed it by carefully re-reading the puzzle description. Then I realized my mistake: I didn't count the 2 picoseconds of cheating as part of the total time. I fixed that by inserting the \"`-2`\" in the last line of `cheats`. In the process of carefully re-reading, I realized that the path through the grid is a single path; I didn't need a queue of points in `all_distances`; the queue will always be just one point. But changing it wouldn't have a big effect on efficiency, so I'll keep it as is.\n",
    "\n",
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/686/544/560/665/267/small/41dc36dd2b873d41.jpg\" width=400>\n",
    "\n",
    "\n",
    "### Part 2: How many big cheats would save you at least 100 picoseconds?\n",
    "\n",
    "In Part 2 we are allowed a much **bigger cheat**, of up to 20 steps (and thus 20 picoseconds). But we can still only use one cheat. I'll tackle this by looking at all points in a neighborhood of radius 20 from each starting point on the path."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 230,
   "id": "e5f15182-68df-4831-b061-660413fdbae4",
   "metadata": {},
   "outputs": [],
   "source": [
    "def big_cheats(racetrack, minimum_savings=1, radius=20) -> Iterable[Tuple[Point, Point, int]]:\n",
    "    \"\"\"All ways of cheating by taking up to `radius` steps through walls and back to the track,\n",
    "    as long as they save at lease `minimum_savings` picoseconds\"\"\"\n",
    "    D = all_distances(racetrack, the(racetrack.findall('E'))) # A dict of {sposition: distance_to_E}\n",
    "    return ((p1, p2, t)\n",
    "            for p1 in D\n",
    "            for p2 in neighborhood(p1, radius)\n",
    "            if  p2 in D and (t := D[p1] - D[p2] - taxi_distance(p1, p2)) >= minimum_savings)\n",
    "\n",
    "def neighborhood(point, radius) -> List[Point]:\n",
    "    \"\"\"All points within `radius` of `point` (using taxi distance).\"\"\"\n",
    "    (x, y) = point\n",
    "    return [(x + dx, y + dy) \n",
    "            for dx in range(-radius, radius + 1)\n",
    "            for dy in range(-(radius - abs(dx)), radius - abs(dx) + 1)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 231,
   "id": "aa9ea31c-26a3-411f-b0ae-df37bea3c8c0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 20.2:   .737 seconds, answer 982891            ok"
      ]
     },
     "execution_count": 231,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(20.2, 982891, lambda:\n",
    "       quantify(big_cheats(racetrack, 100, radius=20)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0022ec12-5359-455f-ace8-c8615d7cd1d2",
   "metadata": {},
   "source": [
    "This solution is backwards-compatible with Part 1:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 233,
   "id": "332e9c72-db9a-4b90-a649-45f7bf955e84",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 20.1:   .022 seconds, answer 1343              ok"
      ]
     },
     "execution_count": 233,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(20.1, 1343, lambda:\n",
    "       quantify(big_cheats(racetrack, 100, radius=2)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6f136dce-d68b-47b1-9b2e-31293f73ed6c",
   "metadata": {},
   "source": [
    "# [Day 21](https://adventofcode.com/2024/day/21): Keypad Conundrum\n",
    "\n",
    "Today's puzzle is simple: unlock the door to Santa's starship by entering some lock codes on a **numeric keypad**. Here are the lock codes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 235,
   "id": "9d0eea9f-9d8f-4410-97ec-13d8b136925b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 5 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "839A\n",
      "169A\n",
      "579A\n",
      "670A\n",
      "638A\n"
     ]
    }
   ],
   "source": [
    "codes = parse(21)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "adeabd3b-f534-4457-ab7e-3f057c34600f",
   "metadata": {},
   "source": [
    "### Part 1: What is the sum of the complexities of the five codes on your list?\n",
    "\n",
    "We know the codes, so what is the difficulty? It turns out the numeric keypad is inaccessible, so we have to get a **robot** to press the buttons, and we have to command the robot's arm by pressing some buttons on a **remote control directional keypad**: arrow keys to move the arm, and the \"`A`\" (activate) button to make the arm press the button it is currently pointing at. Here are the two keypads:\n",
    "\n",
    "        +---+---+---+            +---+---+\n",
    "        | 7 | 8 | 9 |            | ^ | A |\n",
    "        +---+---+---+        +---+---+---+\n",
    "        | 4 | 5 | 6 |        | < | v | > |\n",
    "        +---+---+---+        +---+---+---+\n",
    "        | 1 | 2 | 3 |\n",
    "        +---+---+---+\n",
    "            | 0 | A |\n",
    "            +---+---+\n",
    "        \n",
    "Long story short: it turns out the robot's remote keypad is *also* inaccessible, and we end up needing **three robots**, each pressing buttons on the next keypad, so there are **four levels** of button pressing all together:\n",
    "\n",
    "- You press some buttons on Robot 3's remote keypad (e.g. <vA<<A...)\n",
    "- Robot 3 presses some buttons on Robot 2's remote keypad (e.g. v<<A>>...)\n",
    "- Robot 2 presses some buttons on Robot 1's remote keypad (e.g. <A^A^^AvvvA)\n",
    "- Robot 1 presses some buttons on the door's numeric keypad (e.g. 029A).\n",
    "\n",
    "The robots all initially have their arm pointing at the `'A'` key of their respective target keypads. It is forbidden to command the arm to go off the keypad or to go to the empty corner.\n",
    "\n",
    "We'd like to find the shortest possible sequence of button presses at the top level. Once we've figured out the shortest button sequence to enter each of the codes, we have to compute the **complexity** of each code, which is defined as the integer part of the code times the length of the shortest possible sequence.\n",
    "\n",
    "Here are some considerations:\n",
    "- To get from one button to the next there can be several paths.\n",
    "- For example, to get from \"A\" to \"7\" on the numeric keypad the shortest paths include \"^^^<<\" and \"^<^<^\" and \"<^<^^\".\n",
    "    - But exclude \"<<^^^\", because that would hit the empty corner, which is forbidden.\n",
    "    - Also exclude any sequences with both \">\"  and \"<\", or both \"^\" and \"v\", because that's just wasteful.\n",
    "- Each of these paths have the same length, so if we were directly pressing Robot 1's remote control, any path would do.\n",
    "- However, it might take the robot at the next level a different number of presses to command each of these paths.\n",
    "- To command \"^^^\" the next robot has to command this robot to the \"^\" key and then press \"AAA\". If the \"^\" and \"<\" keys are interspersed, the commands will take more buttons, because there will be navigation between each \"A\". Therefore, I will consider at most two paths: all the horizontal arrows first, or all the vertical arrows first.\n",
    "- Fortunately, whenever there is a button press on the numeric keypad, we know that *all* the robots are on \"A\", because each one must have activated a button press to make the chain of presses happen.\n",
    "- Therefore, the parts of the problem are *decomposible*: at any level, the minimum number of keypresses to, say,  \"get the robot arm from the `^` to the `A` and press it\" will be the same, regardless of what keypresses come before or after. The order doesn't matter on this level, although it may affect other levels.\n",
    "- I could represent a keypad with my `Grid` class, but I don't need what `Grid` provides, all I need is a way to look up the (x, y) location of each key. I'll also explicitly save the (x, y) position of the forbidden empty corner as `keypad.forbidden`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 237,
   "id": "779c6b4c-ceb0-49ac-96f2-4700835c70ea",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Keypad(dict):\n",
    "    \"\"\"A representation of the key positions in a keypad.\"\"\"\n",
    "    def __init__(self, rows):\n",
    "        self.update({char: (x, y) for (y, row) in enumerate(rows) for (x, char) in enumerate(row)})\n",
    "        self.forbidden = self['_']\n",
    "        del self['_']\n",
    "\n",
    "numeric_keypad = Keypad(['789', '456', '123', '_0A'])\n",
    "remote_keypad  = Keypad(['_^A', '<v>'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "486ae303-36cf-4750-965b-3402eec2b625",
   "metadata": {},
   "source": [
    "Now I can compute the remote keypad presses that are required to command a robot to move from `key1` to `key2` and press `key2`.  There will be either one or two possible paths, depending on whether one of them hits the `forbidden` corner."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 239,
   "id": "c915ada2-9dfe-42fe-bd08-855ff5d0e837",
   "metadata": {},
   "outputs": [],
   "source": [
    "def possible_paths(key1, key2, keypad) -> Iterable[str]:\n",
    "    \"\"\"Should we try, e.g. \">>^^A\" or \"^^>>A\", or both, to command\n",
    "    a move from key1 to key2 and press key2 on the target keypad?\"\"\"\n",
    "    pos1, pos2 = keypad[key1], keypad[key2]\n",
    "    (dx, dy) = sub(pos2, pos1)\n",
    "    horizontal = abs(dx) * ('>' if dx > 0 else '<')\n",
    "    vertical   = abs(dy) * ('v' if dy > 0 else '^')\n",
    "    if add(pos1, (dx, 0)) != keypad.forbidden:\n",
    "        yield horizontal + vertical + 'A'\n",
    "    if add(pos1, (0, dy)) != keypad.forbidden: \n",
    "        yield vertical + horizontal + 'A'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9243a77-8466-4aea-bbc9-b10af141e2fb",
   "metadata": {},
   "source": [
    "My first **bug** on today's puzzle was multiplying the arrow character by `dx` instead of `abs(dx)`. Did you know that `-2 * '>'` is the empty string, and not an error? "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "74f1f872-5c0c-4baa-a941-d910dc9c1048",
   "metadata": {},
   "source": [
    "We will need to compute the **complexity** of a code for our final answer:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 242,
   "id": "1e2e8c59-744f-4f36-9251-c8ea5fd60aed",
   "metadata": {},
   "outputs": [],
   "source": [
    "def complexity(code, levels=4): \n",
    "    \"\"\"The integer part of the code times the niminimum number of key presses.\"\"\"\n",
    "    return int(cat(digits(code))) * min_keypresses(code, levels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "975b5719-9afc-4b0a-9e07-c1c2b38059f7",
   "metadata": {},
   "source": [
    "And here's how we compute the minimum number of keypresses:\n",
    "- `total_presses` determines the minimum number of keypresses required to execute a key sequence.\n",
    "  - At level 1, this means just typing the code on the numeric keypad.\n",
    "  - At level 2 and up, it means the number of remote keypad presses needed to command a robot below to execute the key sequence. \n",
    "- `one_button_min_keypresses` is similar, but it determines the  minimum number of keypresses to command just one thing: move from one key to another and press it. We get efficiency from the `@cache` decorator on this method, so even though there are many movements between keys at all levels, we only need to compute each of them once. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 244,
   "id": "eca187c8-4457-4c06-a5a4-d4fd19858325",
   "metadata": {},
   "outputs": [],
   "source": [
    "def min_keypresses(code: str, levels: int) -> int:\n",
    "    \"\"\"The smallest possible number of keypresses (on the top level) to type `code` \n",
    "    on the numeric keypad, if there are `levels` of button-pressers \n",
    "    (all but one of them using the remote keypad).\"\"\"\n",
    "    \n",
    "    def total_presses(keysequence: str, level: int) -> int:\n",
    "        \"\"\"Total presses required to command `keysequence` from this level.\"\"\"\n",
    "        if level == 1:\n",
    "            return len(keysequence) # Just press the code buttons\n",
    "        else:\n",
    "            return sum(one_button_min_keypresses(key1, key2, level)\n",
    "                       for key1, key2 in sliding_window('A' + keysequence, 2))\n",
    "        \n",
    "    @cache\n",
    "    def one_button_min_keypresses(key1: Char, key2: Char, level: int) -> int:\n",
    "        \"\"\"The minimum number of presses to command a press of key2, starting from key1.\"\"\"\n",
    "        keypad = numeric_keypad if level == levels else remote_keypad\n",
    "        return min(total_presses(path, level - 1) \n",
    "                   for path in possible_paths(key1, key2, keypad))\n",
    "\n",
    "    return total_presses(code, levels)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "696ad2eb-244a-4ed1-ac0b-d40a0556090f",
   "metadata": {},
   "source": [
    "Here is the answer, which turns out to be a fairly small number:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 246,
   "id": "393a8c6b-6a1c-4495-aad5-92f48711fbf1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 21.1:   .000 seconds, answer 205160            ok"
      ]
     },
     "execution_count": 246,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(21.1, 205160, lambda:\n",
    "       sum(map(complexity, codes)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08d46094-0ebf-4c84-8ec4-b563630b2458",
   "metadata": {},
   "source": [
    "I was encountering other **bugs** (off-by-one errors, maybe?), so I wrote some code that explicitly built a cache of path lengths. Once I did that I understood the puzzle better and was able to easily write the code above with the cache handled by the decorator, which I think is neater."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a16c8f8-e1e5-47f8-b6c6-4a7500a457e6",
   "metadata": {},
   "source": [
    "### Part 2: With 27 levels, what is the sum of the complexities of the five codes on your list?\n",
    "\n",
    "As I suspected, Part 2 gets us into a [ludicrous](https://www.youtube.com/watch?v=oApAdwuqtn8) number of button presses. The problem is the same, but now there are **27** levels, not **4**. No new code, just sum the complexity  again:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 249,
   "id": "563c5959-692d-4368-8c0b-469fa0142678",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 21.2:   .004 seconds, answer 252473394928452   ok"
      ]
     },
     "execution_count": 249,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(21.2, 252473394928452, lambda:\n",
    "       sum(complexity(code, levels=27) for code in codes))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "56db891e-56c4-4f0a-bab8-545c2ccdbb2c",
   "metadata": {},
   "source": [
    "### Part 3: Verification and Exploration\n",
    "\n",
    "We know the sum of the complexities, but how many button presses are there?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 251,
   "id": "f2d29a66-5420-4fc1-8586-1570ed5ac0a8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "439646398242"
      ]
     },
     "execution_count": 251,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(min_keypresses(code, levels=27) for code in codes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1cf2d848-2f43-48dc-8862-493cebd94558",
   "metadata": {},
   "source": [
    "If we could press one button per millisecond, it would take [**14 years**](https://www.google.com/search?q=439646398242+milliseconds+in+years) to do this number of button presses.\n",
    "\n",
    "Below are some assertions that serve as unit tests and as examples of usage:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 253,
   "id": "4d8c8659-52d3-4349-8465-7003e880502f",
   "metadata": {},
   "outputs": [],
   "source": [
    "assert list(possible_paths('A', '7', numeric_keypad)) == ['^^^<<A']\n",
    "assert list(possible_paths('8', 'A', numeric_keypad)) == ['>vvvA', 'vvv>A']\n",
    "assert list(possible_paths('v', 'A', remote_keypad))  == ['>^A', '^>A']\n",
    "\n",
    "assert list(sliding_window('A029A', 2)) == ['A0', '02', '29', '9A']\n",
    "\n",
    "assert min_keypresses('029A', 1) ==  4 # \"029A\"\n",
    "assert min_keypresses('029A', 2) == 12 # \"<A^A>^^AvvvA\"\n",
    "assert min_keypresses('029A', 3) == 28 # \"v<<A>>^A<A>AvA<^AA>A<vAAA>^A\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29c33a82-0baf-41fd-807f-f7e955b1706a",
   "metadata": {},
   "source": [
    "I considered representing a key sequence as a `Counter` of one button presses. So we would have\n",
    "\n",
    "    min_keypresses('029A', 1) == Counter({'02': 1, '29': 1, '9A': 1})\n",
    "    min_keypresses('029A', 2) == Counter({'^A': 2, 'vv': 2, '<A': 1, 'A^': 1, 'A>': 1, '>^': 1, '^^': 1, 'Av': 1, 'vA': 1})\n",
    "\n",
    "This would take slightly longer to compute, but would give a more informative answer. But I guessed (correctly) that Part 2 would only be interested in the total number of key presses, not the details."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab5218d4-3c0c-47d8-a105-d0dbced92cd4",
   "metadata": {},
   "source": [
    "# [Day 22](https://adventofcode.com/2024/day/22): Monkey Market\n",
    "\n",
    "Today we are introduced to the monkey exchange market. The monkeys are **buyers** of hiding spots,  offering **bananas** as payment. We need bananas, and fortunately we have many hiding spots to sell. Each monkey has a **secret number** (today's input):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 256,
   "id": "2c1e7612-4ec5-4ce1-b591-5c3a14f8ea61",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 1685 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "9524047\n",
      "7448470\n",
      "4573369\n",
      "4782321\n",
      "14221799\n",
      "5609429\n",
      "16652319\n",
      "2515459\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 1685 ints:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "9524047\n",
      "7448470\n",
      "4573369\n",
      "4782321\n",
      "14221799\n",
      "5609429\n",
      "16652319\n",
      "2515459\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "secrets = parse(22, int)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7f4cf5f-0e07-4e61-88ce-c3dfd6e3f0c8",
   "metadata": {},
   "source": [
    "### Part 1: What is the sum of the 2000th secret number generated by each buyer?\n",
    "\n",
    "Each buyer's secret number changes on each time step. There is a detailed process for generating the next secret number from the previous secret number, involving dividing, multiplying, XOR-ing, and taking modulos. We are asked for the sum of each buyer's 2000th next secret number. Easy enough:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 258,
   "id": "3807adbc-261a-4108-88ba-6e2b061526b5",
   "metadata": {},
   "outputs": [],
   "source": [
    "def nth_secret(secret: int, n=2000) -> int:\n",
    "    \"\"\"Compute the `n`th next secret number after this secret number.\"\"\"\n",
    "    for _ in range(n):\n",
    "        secret ^= (secret *   64) % 16777216\n",
    "        secret ^= (secret //  32) % 16777216\n",
    "        secret ^= (secret * 2048) % 16777216\n",
    "    return secret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 259,
   "id": "fce754cd-f6da-4e7d-b406-3314c9c28ca8",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 22.1:   .313 seconds, answer 14273043166       ok"
      ]
     },
     "execution_count": 259,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(22.1, 14273043166, lambda:\n",
    "       sum(map(nth_secret, secrets)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80fea986-b9f3-4184-94b5-5fda551ce115",
   "metadata": {},
   "source": [
    "I note that all the the integer constants in `nth_secret` are powers of 2, so they could be replaced by bit operations. I wonder if I will have to analyze exactly what is going on with these bit operations for Part 2. \n",
    "\n",
    "### Part 2: What is the most bananas you can get?\n",
    "\n",
    "Knowing the timeline of secret numbers is not the whole story. Each buyer monkey has a **price** in bananas that they are offering at each time step. The price is the ones digit of their secret number (e.g., for secret number 9524047 the price is 7 bananas). Each monkey wants to buy exactly one hiding spot. We would like to wait for the highest price offering from each monkey, but we don't speak monkeese. We do have a translator who speaks a few words, but unfortunately, the translator doesn't know enough to help us sell as soon as the price hits 9 (or 8, or whatever). All we can do is the following:\n",
    "\n",
    "- We tell the translator to watch for a specific sequence of four deltas in price in the timeline of any monkey.\n",
    "- For example, we say to watch for the deltas (**+1, -2, 0, +3**).\n",
    "- Say the prices for the first monkey are (3, 3, 3, 5, 6, 4, 4, 7, ...)\n",
    "- Then the deltas are (0, 0, +2, **+1, -2, 0, +3**, ...)\n",
    "- That matches our 4 deltas, so we immediately sell our hiding spot to the monkey for the current price,  7 bananas.\n",
    "- That monkey is now done and won't buy again.\n",
    "- The translator simultaneously monitors all the monkeys, looking for (**+1, -2, 0, +3**).\n",
    "\n",
    "Our task is to get the most possible bananas under these constraints. \n",
    "\n",
    "Can we brute-force it? Each delta is between -9 and +9, so the number of possible 4-tuples of deltas is fairly small, less than 10<sup>5</sup> (5 digits give you all the 4-deltas, but some are duplicates). However, if for each possible 4-tuple of deltas I looked at all 2000 steps of all 1685 monkeys, then 10<sup>5</sup> ✖️ 2000 ✖️ 1685 is more than 300 billion, which is a medium-large number. So instead I'll define `total_bananas` to do this:\n",
    "\n",
    "    Maintain a dict of {4-tuple: total bananas gained}, initially empty\n",
    "    For each monkey:\n",
    "        For each unique 4-tuple of price deltas in the monkey's price timeline:\n",
    "            increment the total number of bananas for this 4-tuple by the current price\n",
    "\n",
    "I'll also define `price_timeline` to give the timeline of unique 4-tuples for one monkey, making sure to only include the first time each 4-tuple appears. In `price_timeline` I could call `nth_secret(secret, 1)`, but I decided to make a separate `next_secret` function. I probably should have done that for Part 1. Finally, take the maximum of the numbers of bananas, across all the recorded 4-tuples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 261,
   "id": "cbbb4793-b13d-4a95-ba03-673b3ebaa229",
   "metadata": {},
   "outputs": [],
   "source": [
    "Deltas = Tuple[int, int, int, int]\n",
    "\n",
    "def total_bananas(secrets: Ints, n=2000) -> Dict[Deltas, int]:\n",
    "    \"\"\"Pairs of {delta-4-tuple: total_bananas_gained} over all secret numbers,\n",
    "    for the first `n` 4-tuples of deltas.\"\"\"\n",
    "    bananas = defaultdict(int)  # {deltas: total_bananas}\n",
    "    for secret in secrets: # For each monkey ...\n",
    "        for deltas, price in price_timeline(secret, n).items():\n",
    "            bananas[deltas] += price\n",
    "    return bananas\n",
    "\n",
    "def price_timeline(secret, n=2000) -> Dict[Deltas, int]:\n",
    "    \"\"\"Each {delta-4-tuple: price} in the timeline of this secret number, \n",
    "    for `n` steps, but only the first time each unique delta-4-tuple appears.\"\"\"\n",
    "    timeline = {}             # {delta-4-tuple: price} pairs\n",
    "    deltas = ()               # The 4 most recent price deltas  \n",
    "    price = secret % 10       # Initial price\n",
    "    for _ in range(n):\n",
    "        secret = next_secret(secret)\n",
    "        price, previous_price = secret % 10, price\n",
    "        deltas = (*deltas[-3:], price - previous_price)\n",
    "        if len(deltas) == 4 and deltas not in timeline:\n",
    "            timeline[deltas] = price\n",
    "    return timeline\n",
    "\n",
    "def next_secret(secret: int) -> int:\n",
    "    \"\"\"Compute the next secret number after this secret number.\"\"\"\n",
    "    secret ^= (secret *   64) % 16777216\n",
    "    secret ^= (secret //  32) % 16777216\n",
    "    secret ^= (secret * 2048) % 16777216\n",
    "    return secret"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 262,
   "id": "34eaf7fe-fe9b-4858-b1e8-e4c3713ea093",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 22.2:  1.108 seconds, answer 1667              ok"
      ]
     },
     "execution_count": 262,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(22.2, 1667, lambda:\n",
    "    max(total_bananas(secrets).values()))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bfc067a9-e6de-4390-bf78-3da283d68465",
   "metadata": {},
   "source": [
    "### Part 3: Exploration\n",
    "\n",
    "I'm surprised the answer is so low; less than one banana per monkey. I would have guessed more like 4 per monkey. And yet it is the correct answer. Let's investigate. First, what is the best 4-tuple of deltas?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 264,
   "id": "a2da8c78-d240-4c52-a83a-f3599f4f69a4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-3, 2, -1, 2)"
      ]
     },
     "execution_count": 264,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bananas = total_bananas(secrets)\n",
    "best_deltas = max(bananas, key=bananas.get) \n",
    "best_deltas"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e1c48b3-bfff-4e5d-8f6f-9c9fff5f6baa",
   "metadata": {},
   "source": [
    "Now, how many monkeys had this 4-tuple in their timeline, and what prices did each buy at? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 266,
   "id": "9de3f365-c546-494a-a18c-2ae58d88792b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "271 monkeys (16%) bought, total price 1667, mean 6.2,\n",
      "Histogram of prices: {3: 43, 4: 34, 5: 33, 6: 32, 7: 37, 8: 42, 9: 50}\n"
     ]
    }
   ],
   "source": [
    "prices = [p for secret in secrets for d, p in price_timeline(secret).items() if d == best_deltas]\n",
    "hist = {i: prices.count(i) for i in range(10) if i in prices}\n",
    "print(f'{len(prices)} monkeys ({len(prices)/len(secrets):.0%}) bought, '\n",
    "      f'total price {sum(prices)}, mean {mean(prices):3.1f},\\n'\n",
    "      f'Histogram of prices: {hist}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7fac136e-b676-49c9-91f1-a209b9ef53fa",
   "metadata": {},
   "source": [
    "We do pretty well on prices, getting a lot of 8 and 9 prices, and nothing less than 3, but only 271  monkeys (16%) every get the `best_deltas` sequence.\n",
    "\n",
    "Do any 4-tuples show up in more timelines?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 268,
   "id": "4fc191f9-62d8-47ef-a571-8c0541e25f4d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[((0, -1, 1, -1), 322),\n",
       " ((-1, 0, 0, 0), 315),\n",
       " ((0, -1, 0, 0), 315),\n",
       " ((-1, 0, 1, 0), 312),\n",
       " ((1, -2, 1, 0), 303),\n",
       " ((0, 1, -1, 0), 302),\n",
       " ((0, 0, 0, 0), 297),\n",
       " ((0, 1, 0, 0), 295),\n",
       " ((0, 1, 0, -1), 295),\n",
       " ((1, -1, 0, 0), 292)]"
      ]
     },
     "execution_count": 268,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Counter(flatten(map(price_timeline, secrets))).most_common(10)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fa741c6-ecf7-4459-a017-ffa574352d7e",
   "metadata": {},
   "source": [
    "Yes, but not by that much: 322 monkeys is 19% more than the 271 monkeys for the best 4-tuple, but the total number of bananas is less:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 270,
   "id": "bbd329a0-309c-4c81-a780-6bd97a95f652",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1341"
      ]
     },
     "execution_count": 270,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bananas[(0, -1, 1, -1)]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "58c39447-f458-4254-bb4c-144effd3f23c",
   "metadata": {},
   "source": [
    "I was also curious about exactly how many possible *n*-tuples of deltas there are for any sequence of *n* digits (not just from the secrets):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 272,
   "id": "a2945c44-00f7-4c88-9b6e-747d9563034e",
   "metadata": {},
   "outputs": [],
   "source": [
    "def all_deltas(digits=range(10), n=4) -> Counter[Tuple[int, ...]]:\n",
    "    \"\"\"What `n`-tuples of deltas are possible for all sequences of `n`+1 `digits`,\n",
    "    and how many ways can each of them occur?\"\"\"\n",
    "    sequences = cross_product(digits, repeat=n+1)\n",
    "    return Counter(tuple(seq[i + 1] - seq[i] for i in range(n))\n",
    "                   for seq in sequences)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e8e0ea9-b617-43fc-83dc-767511ce63a6",
   "metadata": {},
   "source": [
    "First a small example, with only two digits:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 274,
   "id": "936bfa40-726a-4ddd-8033-8a50fa09b9ea",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({(0, 0, 0): 2,\n",
       "         (0, 0, 1): 1,\n",
       "         (0, 1, -1): 1,\n",
       "         (0, 1, 0): 1,\n",
       "         (1, -1, 0): 1,\n",
       "         (1, -1, 1): 1,\n",
       "         (1, 0, -1): 1,\n",
       "         (1, 0, 0): 1,\n",
       "         (-1, 0, 0): 1,\n",
       "         (-1, 0, 1): 1,\n",
       "         (-1, 1, -1): 1,\n",
       "         (-1, 1, 0): 1,\n",
       "         (0, -1, 0): 1,\n",
       "         (0, -1, 1): 1,\n",
       "         (0, 0, -1): 1})"
      ]
     },
     "execution_count": 274,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "all_deltas(digits=(0, 1), n=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "068355da-13fb-4076-a7ce-29fccf83bb14",
   "metadata": {},
   "source": [
    "With 2 digits there are 2<sup>4</sup> sequences of length 4 that make (2<sup>4</sup> - 1) unique delta 3-tuples, because the sequence (0, 0, 0, 0) and (1, 1, 1, 1) both yield the deltas (0, 0, 0). The pattern holds for other lengths with two digits:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 276,
   "id": "9dac4989-6fc8-4b45-87de-6dcfca7a91c9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{2: 7, 3: 15, 4: 31, 5: 63, 6: 127, 7: 255, 8: 511, 9: 1023}"
      ]
     },
     "execution_count": 276,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{n: len(all_deltas(digits=range(2), n=n)) for n in range(2, 10)}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73a92c4f-06e8-4266-a6ef-68074dc0b8ce",
   "metadata": {},
   "source": [
    "Now we try with 10 digits, for tuples of length 1 to 5:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 278,
   "id": "2bb368b8-d5e7-431c-bd2c-19aa41983b8d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 19, 2: 271, 3: 3439, 4: 40951, 5: 468559}"
      ]
     },
     "execution_count": 278,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "{n: len(all_deltas(digits=range(10), n=n)) for n in range(1, 6)}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47add4c5-499a-4c6f-a148-74093a72e3c7",
   "metadata": {},
   "source": [
    "This sequence of integers, 19, 271, 3439, 40951, 468559 [**appears**](https://oeis.org/search?q=+1%2C+19%2C+271%2C+3439%2C+40951&language=english&go=Search)  in the Online Encyclopedia of Integer Sequences (OEIS), a great resource for looking up a sequence of integers. It is not described as having anything to do with deltas, but rather as 10<sup>*n*</sup> - 9<sup>*n*</sup>."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd6330b8-9ddd-4d58-9314-83b47cb2fb78",
   "metadata": {},
   "source": [
    "# [Day 23](https://adventofcode.com/2024/day/23): LAN Party\n",
    "\n",
    "We see that there is a LAN party scheduled for today. Our input is a network map of bidirectional connections between computers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 281,
   "id": "85f5b145-8c5e-448c-8b45-ad5750252ff2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 3380 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "ht-nz\n",
      "pt-uj\n",
      "nr-me\n",
      "qq-up\n",
      "zr-pa\n",
      "ly-wv\n",
      "ei-ry\n",
      "sm-md\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 3380 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "('ht', 'nz')\n",
      "('pt', 'uj')\n",
      "('nr', 'me')\n",
      "('qq', 'up')\n",
      "('zr', 'pa')\n",
      "('ly', 'wv')\n",
      "('ei', 'ry')\n",
      "('sm', 'md')\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "network = parse(23, atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a22e4214-736c-477a-810c-e77fcd68f1b4",
   "metadata": {},
   "source": [
    "### Part 1: Find all the sets of three inter-connected computers. How many contain at least one computer with a name that starts with t?\n",
    "\n",
    "We're asked to find three inter-connected computers, e.g., three computers A, B, C, such that A-B, B-C, and C-A are all in the list of connections (but connections are bidirectional, so either A-B or B-A could be in the input). A set where every node is connected to every other is called a **clique**. I'll represent the network **graph** as a dict of the form `{A: {B, C}}` to denote that node `A` is connected to `B` and `C`. The function `bidrected_graph` forms a graph from an iterable of (A, B) connections. Then `triples_starting_with` finds all cliques of size 3, where at least one of them starts with the given letter. The procedure could find duplicates (e.g. both (A, B, C) and (C, B, A), so I represent each triple as a frozenset and eliminate duplicates by returning the set of them. The answer for Part 1 is then the number of triples that start with `t`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 283,
   "id": "289d2325-1e58-41f5-b4b2-b90ae26e7887",
   "metadata": {},
   "outputs": [],
   "source": [
    "Clique = set # A clique is a set of nodes\n",
    "\n",
    "def bidirected_graph(connections) -> dict:\n",
    "    \"\"\"A graph where, e.g., {A: {B, C}} means A is connected to B and C.\"\"\"\n",
    "    graph = defaultdict(set)\n",
    "    for (A, B) in connections:\n",
    "        graph[A].add(B)\n",
    "        graph[B].add(A)\n",
    "    return graph\n",
    "\n",
    "def triples_starting_with(graph, start='') -> Set[Clique]:\n",
    "    \"\"\"All cliques of 3 nodes, where at least one of them starts with the letter `start`.\"\"\"\n",
    "    return {frozenset((A, B, C)) \n",
    "            for A in graph if A.startswith(start)\n",
    "            for B in graph[A]\n",
    "            for C in graph[B] if C in graph[A]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 284,
   "id": "6425577d-4ca9-45de-9698-cd9b026f7ce6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 23.1:   .001 seconds, answer 1170              ok"
      ]
     },
     "execution_count": 284,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(23.1, 1170, lambda:\n",
    "       len(triples_starting_with(bidirected_graph(network), 't')))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af420aeb-314b-4750-a424-7daad0ffdd62",
   "metadata": {},
   "source": [
    "### Part 2: What is the password to get into the LAN party?\n",
    "\n",
    "In Part 2 we are asked to figure out the password for the LAN party. We learn two important facts: \n",
    "- The LAN party is the maximum **clique** in the graph (the clique wwith the most members).\n",
    "- The **password** is formed by listing the names of all the computers in the LAN party in alphabetical order, separatied by commas.\n",
    "\n",
    "The function `maximum_clique` finds the largest clique; and `password` creates the password. The function `expand_clique` takes a clique, a node, and a graph. It expands out from the node, recursively looking for and adding any other nodes that should be added to the clique, finally returning the clique. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 286,
   "id": "c497adf7-caee-4ced-9d62-0a589879b460",
   "metadata": {},
   "outputs": [],
   "source": [
    "def maximum_clique(graph) -> Clique: \n",
    "    \"\"\"The clique in `graph` with the most members.\"\"\"\n",
    "    return max([expand_clique({A}, A, graph) for A in graph], key=len)\n",
    "    \n",
    "def expand_clique(clique, A, graph) -> Clique:\n",
    "    \"\"\"Expand out from node A, adding nodes to `clique` as long as they form a clique.\"\"\"\n",
    "    for B in graph[A]:\n",
    "        if B not in clique and clique.issubset(graph[B]):\n",
    "            clique.add(B)\n",
    "            expand_clique(clique, B, graph)\n",
    "    return clique\n",
    "\n",
    "def password(clique) -> str: return ','.join(sorted(clique))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 287,
   "id": "0b5f08ac-18e2-4933-9737-cdbc842c5809",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 23.2:   .003 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok"
      ]
     },
     "execution_count": 287,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(23.2, 'bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg', lambda:\n",
    "       password(maximum_clique(bidirected_graph(network))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "859914ff-6ec5-4251-b3b9-bcd099f327c3",
   "metadata": {},
   "source": [
    "### Part 3: Exploration\n",
    "\n",
    "*Terminology note:* A **maximum clique** is a largest clique in the graph. A **maximal clique** is a clique to which no other node can be added to form a larger clique. Say there are 3 nodes that form a triangle. That's a clique. But if there is a fourth node that is connected to all three nodes in the triangle, then that too is a clique, and it means the triangle is not a maximal clique."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "197986f5-61b2-4e9e-929a-c1ba440b3550",
   "metadata": {},
   "source": [
    "*Second thoughts:* I got the right answer, and I coded it up quickly (for me) without errors, and it runs in under 1/10 second. But it is not the most efficient algorithm, because if a clique has *n* nodes, that clique will be re-generated *n* times.  Since the maximum clique on my graph is only 13 members, that's not so bad, but don't use my algorithm on a graph with million-element cliques.\n",
    "\n",
    "I'm also not completely sure my algorithm handles all possible inputs. Consider the following network, where `{BCD}` means the three nodes form a (non-maximal) clique, and a dashed line means all nodes on each side are connected.\n",
    "\n",
    "    {BCD}--{A}--{EF}\n",
    "\n",
    "The call to `expand_cliqe(A, ...)` might return either `{ABCD}` or `{AEF}`, so it might miss the maximum clique. For this example, if we missed on `A`, we would still get `{ABCD}` from `B` or `C` or `D`. But I can't quite prove there can't be some more complex configurations where my algorithm fails."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88d8883e-922a-4d08-bbec-a01d5bf225ef",
   "metadata": {},
   "source": [
    "# [Day 24](https://adventofcode.com/2024/day/24): Crossed Wire\n",
    "\n",
    "Today we are trying to help the historian to debug a malfunctioning **monitoring device**, which consistes of some wires and logic gates. The day's input describes the connections in the device. There are two types of inputs: an input wire is described with its name and its bit value: `x00: 1`, and a logic gate is described with the two input wire names, the operation, and the output wire name: `cng XOR mwt -> z42`.\n",
    "\n",
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/709/889/001/483/227/small/5803deed6973ab22.jpg\" width=400>\n",
    "\n",
    "For now I'll just parse each line as a tuple of atoms: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 291,
   "id": "47421581-71df-4c72-a62e-c40d0596fdbb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 313 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "x00: 1\n",
      "x01: 1\n",
      "x02: 0\n",
      "x03: 0\n",
      "x04: 0\n",
      "x05: 1\n",
      "x06: 0\n",
      "x07: 1\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 313 tuples:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "('x00', 1)\n",
      "('x01', 1)\n",
      "('x02', 0)\n",
      "('x03', 0)\n",
      "('x04', 0)\n",
      "('x05', 1)\n",
      "('x06', 0)\n",
      "('x07', 1)\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "connections = parse(24, atoms)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "354dd8da-2737-45c2-af8c-b4b30584ae9a",
   "metadata": {},
   "source": [
    "### Part 1: Simulate the system of gates and wires. What decimal number does it output on the wires starting with z?\n",
    "\n",
    "We can't just treat the device as a program where we execute statements in order, because in a statement like `z42 = cng XOR mwt`, the values of `cng` and `mwt` may not yet be determined. But we can execute *backwards*, as a [dataflow architecture](https://en.wikipedia.org/wiki/Dataflow_architecture). To go backwards we'll need a mapping from each output wire to where it comes from: either a bit value or a gate. I'll define `Device` as a subclass of `dict` to implement this mapping, given the sequence of connections."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 293,
   "id": "43b29260-d912-4cfc-91ce-d303ec1c86df",
   "metadata": {},
   "outputs": [],
   "source": [
    "Wire = str                    # Type for a wire, like `x01`\n",
    "Gate = Tuple[Wire, str, Wire] # Type for a gate, like ('x01', 'AND', 'y01')\n",
    "\n",
    "class Device(dict):\n",
    "    \"\"\"A mapping of {wire_name: bit_value_or_gate}, as specified by the connections.\"\"\"\n",
    "    def __init__(self, connections: Sequence[Tuple[str]]):\n",
    "        for connection in connections:\n",
    "            match connection: \n",
    "                case (wire, bit):      # e.g., ('x00', 1)\n",
    "                    self[wire] = bit\n",
    "                case (x, op, y, wire): # e.g., ('y33', 'AND', 'x33', 'bfn')\n",
    "                    self[wire] = (x, op, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff09bc35-43a4-45c1-bc00-c9cd6a1d7f69",
   "metadata": {},
   "source": [
    "Next, the function `simulate` does the dataflow computation. We start from the outputs (the wires whose first letter is `'z'`) and try to **get** their values. If the value is a bit, great, we got it. If the value is a gate, then we recursively **get** the values of both of the gate's input wires, and perform the gate's boolean operation on them. When we're done calculating all the output variables, the function `simulate` returns their values as a string of `'0'` or `'1'` characters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 295,
   "id": "a9a4780f-6033-452f-b49c-74b97c9e2440",
   "metadata": {},
   "outputs": [],
   "source": [
    "def simulate(device: Device) -> str:\n",
    "    \"\"\"Use dataflow to get the values of the output bits of this device (as a \"01...\" str).\"\"\"\n",
    "    def get(w) -> int: \n",
    "        match device[w]:\n",
    "            case (x, 'AND', y): return get(x) & get(y)\n",
    "            case (x, 'OR',  y): return get(x) | get(y)\n",
    "            case (x, 'XOR', y): return get(x) ^ get(y)\n",
    "            case bit:           return bit\n",
    "    return cat(map(get, wires(device, 'z')))\n",
    "\n",
    "def wires(device: Device, letter: str) -> List[str]: \n",
    "    \"\"\"The names of all the wires that start with the given letter, in sorted order.\"\"\"\n",
    "    return sorted([w for w in device if w.startswith(letter)], reverse=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 296,
   "id": "72437439-dddf-4202-9944-36e796800304",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 24.1:   .001 seconds, answer 36035961805936    ok"
      ]
     },
     "execution_count": 296,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(24.1, 36035961805936, lambda:\n",
    "   int(simulate(Device(connections)), base=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ddc7897-5ff2-46bc-999d-302c92c137da",
   "metadata": {},
   "source": [
    "At first I fell victim to one of the [**classic blunders**](https://youtu.be/RWW6aDpUvbQ?si=0uvZFEYgY9i_441N): using the wrong [**endianness**](https://en.wikipedia.org/wiki/Endianness) of my bits. After re-reading the puzzle description, I fixed the **bug** by adding `reverse=True` to `wires`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c42bd211-b999-4dd8-9e34-aebf042e55e4",
   "metadata": {},
   "source": [
    "### Part 2: What do you get if you sort the names of the eight wires involved in a swap and then join those names with commas?\n",
    "\n",
    "In Part 2 we are told that the device is attempting to do **binary addition**: treating the `x` wires as a binary number and the `y` wires as another binary number, and computing their sum on the `z` wires. However, four pairs of output wires are miswired: they are swapped with each other. Our job is to find all eight wires. \n",
    "\n",
    "I have four ideas of how to proceed, with arguments for and against each of them:\n",
    "1) **Plot** the circuit diagram and look at it to see if anything looks funny.\n",
    "    - I think I could lay out the XORs, ANDs, and ORs in a nice display.\n",
    "    - Connecting the wires would be messy, since wires split and cross. Seems too hard.\n",
    "2) **Examine properties** of the structure of the device and look for something that breaks the pattern.\n",
    "    - For example, make a table of circuit depths of each output wire, and see if one looks wrong.\n",
    "    - This might help me, as a detective, uncover the answer, but if I was given another input device I'd have to start all over.\n",
    "3) **Simulate** the circuit on known `z = x + y` examples and see where it goes wrong.\n",
    "    - If I chose random numbers to add it would take a long time to isolate the faults.\n",
    "    - It is easy to identify faulty output (`z`) values; trickier to assign blame to internal gates.\n",
    "    - I could test the one-bit adders one at a time (e.g. 2<sup>10</sup> + 2<sup>10</sup> = 2<sup>11</sup>) (with and without carry). I think that would find all the bit-positions where the faults are, but we would still need to find the wires that are wrong within that bit's adder.\n",
    "4) **Compare** a conventional adder to the circuit.\n",
    "    - I know how an adder circuit is conventionally built; if our device is like that, we should be able to see where it goes wrong.\n",
    "    - It could be that the device is a correct adder, but is built in a non-conventional way."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3691add5-cd06-4b74-ac5a-7569a1ccb081",
   "metadata": {},
   "source": [
    "I started with approach (2). A simple thing to try is to look at all the gates that lead directly to the outputs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 300,
   "id": "9021ad30-f505-4164-9feb-5af740632182",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'z45': ('nrv', 'OR', 'jsp'),\n",
       " 'z44': ('jsg', 'XOR', 'hks'),\n",
       " 'z43': ('gsk', 'XOR', 'fhk'),\n",
       " 'z42': ('cng', 'XOR', 'mwt'),\n",
       " 'z41': ('jhg', 'XOR', 'gfd'),\n",
       " 'z40': ('nns', 'XOR', 'jbd'),\n",
       " 'z39': ('vqf', 'XOR', 'fkq'),\n",
       " 'z38': ('sqj', 'XOR', 'wts'),\n",
       " 'z37': ('jgw', 'OR', 'rhh'),\n",
       " 'z36': ('rfq', 'XOR', 'hbh'),\n",
       " 'z35': ('djt', 'XOR', 'khf'),\n",
       " 'z34': ('jmv', 'XOR', 'nss'),\n",
       " 'z33': ('dts', 'XOR', 'wmq'),\n",
       " 'z32': ('rck', 'XOR', 'ftq'),\n",
       " 'z31': ('rms', 'XOR', 'sgf'),\n",
       " 'z30': ('pwp', 'XOR', 'nnn'),\n",
       " 'z29': ('tsk', 'XOR', 'hvc'),\n",
       " 'z28': ('msf', 'XOR', 'kdd'),\n",
       " 'z27': ('tvf', 'XOR', 'cmb'),\n",
       " 'z26': ('wkb', 'XOR', 'jkr'),\n",
       " 'z25': ('pfc', 'XOR', 'prp'),\n",
       " 'z24': ('gww', 'XOR', 'jmf'),\n",
       " 'z23': ('mcp', 'XOR', 'mkf'),\n",
       " 'z22': ('wwp', 'XOR', 'bvr'),\n",
       " 'z21': ('qpm', 'XOR', 'csw'),\n",
       " 'z20': ('bvw', 'XOR', 'hvn'),\n",
       " 'z19': ('y19', 'AND', 'x19'),\n",
       " 'z18': ('qvq', 'XOR', 'hns'),\n",
       " 'z17': ('wrc', 'XOR', 'hbw'),\n",
       " 'z16': ('rvn', 'XOR', 'kbq'),\n",
       " 'z15': ('skh', 'XOR', 'rkt'),\n",
       " 'z14': ('cgg', 'XOR', 'rhf'),\n",
       " 'z13': ('jkm', 'XOR', 'dmp'),\n",
       " 'z12': ('htn', 'XOR', 'dtq'),\n",
       " 'z11': ('gkc', 'AND', 'qqw'),\n",
       " 'z10': ('kmr', 'XOR', 'rmb'),\n",
       " 'z09': ('wpb', 'XOR', 'kbb'),\n",
       " 'z08': ('rjs', 'XOR', 'tmg'),\n",
       " 'z07': ('qmb', 'XOR', 'qpc'),\n",
       " 'z06': ('jtg', 'XOR', 'cfn'),\n",
       " 'z05': ('whf', 'XOR', 'fds'),\n",
       " 'z04': ('jvf', 'XOR', 'jth'),\n",
       " 'z03': ('wvt', 'XOR', 'sbt'),\n",
       " 'z02': ('rvm', 'XOR', 'vdq'),\n",
       " 'z01': ('hjp', 'XOR', 'kjs'),\n",
       " 'z00': ('x00', 'XOR', 'y00')}"
      ]
     },
     "execution_count": 300,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "device = Device(connections)\n",
    "{z: device[z] for z in wires(device, 'z')}"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "aadf7dfc-32a1-4409-9f61-ae08741868ef",
   "metadata": {},
   "source": [
    "Right away I can see three anomalies: \n",
    "- `z37` has an OR gate instead of an XOR.\n",
    "- `z19` connects directly to the inputs `x19` and `y19`; no other `z` does that (except `z00`, because it has no carry bit).\n",
    "- `z11` has an AND gate instead of an XOR.\n",
    "\n",
    "I'm already **3/8** of the way there! I tried a few other things but didn't make progress, so I decided to try approach (4): comparing this device to a conventional adder circuit. Here's a picture of a (one-bit) full adder:\n",
    "\n",
    "<img src=\"https://norvig.com/full-adder.jpg\" width=400>\n",
    "\n",
    "The inputs are X and Y and the output is Z (in our device these will be numbered, such as `x01`, `y01`, `z01`).  There is a \"CARRY IN\" wire that comes from the \"CARRY OUT\" of the previous full adder circuit.  Note that there are only two steps from the X, Y inputs to the Z output, so we should be able to handle all the ways those two steps can go wrong.  \n",
    "\n",
    "All together, the circuit has two AND gates, two XOR gates, and an OR gate. We'll need a copy of this circuit for each of the `z01` through `z44` outputs. For `z00` there is no carry bit coming in, so we only need one XOR (to compute `z00`) and one AND (for the \"CARRY OUT\"). Output `z45` is just the \"carry out\" of the circuit for `z44`, so needs no additional gates for `z45`. Let's see if this analysis matches the number of gates that are actually in our device:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 302,
   "id": "b35c397d-6b68-4ba6-bb46-806a449f1398",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Counter({'AND': 89, 'XOR': 89, 'OR': 44})"
      ]
     },
     "execution_count": 302,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "gates = set(device.values()) - {0, 1}\n",
    "Counter(op for (_, op, _) in gates)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ecef107-6764-4d9b-b89c-d499ce280ea5",
   "metadata": {},
   "source": [
    "That looks right, so I speculate that our device is indeed implementing the conventional adder circuit layout.  So my strategy is:\n",
    "- For each input from `(x00, y00)` up to `(x44, y44)`, compare the theoretical gates (XOR1, XOR2, AND1, AND2, OR1) to the actual gates in the device.\n",
    "- If there is a discrepancy, swap wires to fix it up.\n",
    "- I will do this incrementally, adding code to swap wires for each case where I notice there is a problem. (I really *should* analyze *all* possible ways that a swap could occur, but that would be more work; instead I stopped when I had found the four swaps that were needed for my device.)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccc8e2e8-ebe9-480c-b750-e12e28726efe",
   "metadata": {},
   "source": [
    "The first problem I ran into was that the two inputs to a gate could be in either order.  The function `gate` will canonicalize the order so that the alphabetically first wire always is first in the gate. I'll redefine `Device` to use `gate`, and also to cache the inverse mapping: from gates to **output** wires."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 305,
   "id": "ec8d86d4-8caf-40f2-b516-c7da4acbda19",
   "metadata": {},
   "outputs": [],
   "source": [
    "class Device(dict):\n",
    "    \"\"\"A mapping of {wire_name: bit_value_or_gate}, as specified by the connections.\n",
    "    Also caches {gate: output_wire} under self.outputs\"\"\"\n",
    "    def __init__(self, connections: Sequence[Tuple[str]]):\n",
    "        for connection in connections:\n",
    "            match connection: \n",
    "                case (wire, bit):      # e.g., ('x00', 1)\n",
    "                    self[wire] = bit\n",
    "                case (x, op, y, wire): # e.g., ('y33', 'AND', 'x33', 'bfn')\n",
    "                    self[wire] = gate(x, op, y)\n",
    "        self.compute_outputs()\n",
    "        \n",
    "    def compute_outputs(self):\n",
    "        \"\"\"Make a mapping {gate: output_wire} for all gates.\"\"\"\n",
    "        self.outputs = {self[w]: w for w in self if self[w] not in (0, 1)} \n",
    "                    \n",
    "def gate(x, op, y) -> Tuple: \n",
    "    \"\"\"The canonical ordering of the three components of a gate (two input wires and the operator).\"\"\"\n",
    "    return (min(x, y), op, max(x, y))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0786ab78-12d8-4a19-bfca-4bd35a122a3f",
   "metadata": {},
   "source": [
    "Now the hard part. My function `find_swaps` will do the work by working its way through a theoretical conventional adder, and comparing it to the actual device. It first handles the special case for for the first bit, `x00 AND y00 -> z00`, and then for each bit from `00` to `44`, it creates the five gates that make up the adder for that bit, and updates the carry bit (which will be used by the  adder for the next bit), basically like this:\n",
    "  \n",
    "         XOR1 = gate(x, 'XOR', y)\n",
    "         XOR2 = gate(out(XOR1), 'XOR', carry)\n",
    "         AND1 = gate(x, 'AND', y)\n",
    "         AND2 = gate(out(XOR1), 'AND', carry)\n",
    "         OR1  = gate(out(AND1), 'OR', out(AND2))\n",
    "         carry = out(OR1)\n",
    "\n",
    "This gives me a skeleton for my `find_swaps` function. I ran it, and it gave me an error message: a theoretical  gate that I expected to be there was not actually in the device; some wires were crossed. I added code to fix that case, ran the function again, got another error, fixed that, and (somewhat surprisingly to me) that was all it took: I had found the eight faulty wires. Both errors center around the XOR2 gate, which should output the current `z` wire. Here's how I handle it:\n",
    "  - I define XOR2 as the theoretical gate (working forward from `x` and `y`) and XORz as the actual gate in the device (working backwards from `z`).\n",
    "      - In a correct device, the two will be the same. In that case, keep calm and carry on.\n",
    "  - If the XOR2 gate is in the device, but does not have the current `z` wire as output, then:\n",
    "      - Swap the output of the XOR2 with the current `z` wire.\n",
    "  - If the XOR2 gate does not exist in the device, then:\n",
    "      - I assume there is an error in one of the inputs to the XOR2.\n",
    "      - If both inputs are separately faulty, that might be against the rules(?).\n",
    "      - `wire1, wire2 = inputs(XOR2) ^ inputs(XORz)` finds the two wires that appear in one of the gates but not the other.\n",
    "      - Swap wire1 and wire2."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 307,
   "id": "1f259a97-dbad-40dc-903d-6436a77e1903",
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_swaps(device, verbose=False) -> Iterable[str]:\n",
    "    \"\"\"For each bit position, look forward from the inputs, x and y, for the\n",
    "    XOR and AND gates they participate in, then look backwards from the \n",
    "    corresponding z output, and see where they fail to match up.\n",
    "    Swap wires accordingly, and yield each swapped wire.\n",
    "    If `verbose` is true, print debugging information.\"\"\"\n",
    "    \n",
    "    def out(a_gate: Tuple[str, str, str]) -> Wire:  \n",
    "        \"\"\"The name of the output wire for this gate.\"\"\"\n",
    "        return device.outputs[*a_gate]\n",
    "\n",
    "    def swap(a: Wire, b: Wire, debug_msg: str) -> Tuple[str]:\n",
    "        \"\"\"Swap wires `a` and `b` in device.\"\"\"\n",
    "        if verbose: print(f'swap ({a}, {b}) because {debug_msg}')\n",
    "        device[a], device[b] = device[b], device[a]\n",
    "        device.compute_outputs() # Recompute outputs after this swap\n",
    "        return a, b\n",
    "\n",
    "    for i in range(len(wires(device, 'x'))):\n",
    "        x, y, z = [f'{v}{i:02d}' for v in 'xyz'] # e.g. x, y, z = 'x01', 'y01', 'z01'\n",
    "        AND1 = gate(x, 'AND', y)\n",
    "        if x == 'x00':\n",
    "            carry = out(AND1)\n",
    "        else:\n",
    "            XOR1 = gate(x, 'XOR', y)\n",
    "            XOR2 = gate(out(XOR1), 'XOR', carry)\n",
    "            XORz = device[z]  # The gate that `z` expects to get\n",
    "            if XOR2 == XORz:\n",
    "                pass # Keep calm and carry on\n",
    "            elif XOR2 in device.outputs:\n",
    "                yield from swap(out(XOR2), z, f'XOR2_{i} -> {out(XOR2)}, but should -> {z}.')\n",
    "            else: # There is a discrepancy; find the 2 wires not shared between XOR2 and XORz\n",
    "                counts = Counter(XOR2 + XORz)\n",
    "                a, b = [wire for wire in counts if counts[wire] == 1] # Assumes there will be 2 such wires\n",
    "                yield from swap(a, b, f'XOR2_{i} is {XOR2}, but z{i} expects {XORz}.')\n",
    "            AND2 = gate(out(XOR1), 'AND', carry)\n",
    "            OR1  = gate(out(AND1), 'OR', out(AND2))\n",
    "            carry = out(OR1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 308,
   "id": "e9b87c38-f67c-4948-9af6-251021747e9d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 24.2:   .000 seconds, answer jqf,mdd,skh,wpd,wts,z11,z19,z37 ok"
      ]
     },
     "execution_count": 308,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(24.2, 'jqf,mdd,skh,wpd,wts,z11,z19,z37', lambda:\n",
    "       ','.join(sorted(find_swaps(Device(connections)))))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4741dac-4221-4770-bc53-4bb92da229ea",
   "metadata": {},
   "source": [
    "### Part 3: Debugging and Reflections\n",
    "\n",
    "Here I show the debugging output turned on:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 310,
   "id": "dafe10de-c35e-4b01-9517-f048670002b3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "swap (wpd, z11) because XOR2_11 -> wpd, but should -> z11.\n",
      "swap (jqf, skh) because XOR2_15 is ('jqf', 'XOR', 'rkt'), but z15 expects ('rkt', 'XOR', 'skh').\n",
      "swap (mdd, z19) because XOR2_19 -> mdd, but should -> z19.\n",
      "swap (wts, z37) because XOR2_37 -> wts, but should -> z37.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['wpd', 'z11', 'jqf', 'skh', 'mdd', 'z19', 'wts', 'z37']"
      ]
     },
     "execution_count": 310,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(find_swaps(Device(connections), verbose=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a9f0deaa-6695-4dec-ac17-fbceb8958483",
   "metadata": {},
   "source": [
    "I got the correct answer, but it was disapointing because it felt like my strategy was \"hack on it until it works on my one input, with no guarantee that it will work on any other input.\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b8d3967e-3473-47b0-b1b8-687c56e49138",
   "metadata": {},
   "source": [
    "# [Day 25](https://adventofcode.com/2024/day/25): Code Chronicle\n",
    "\n",
    "We're trying to get into the Chief Historian's office, but the door is locked. We have the schematics of all the **locks** and **keys** on the floor we're on, and we need to see which key could fit which lock. A lock schematic has 5 columns of different length growing down from the top, and a key schematic has five columns growing up from the bottom. A key and a lock are a possible fit if none of the five lines overlap; that is, since the lock cylinder has a height of 7 units, it is a possible fit if none of the five columns has more than 7 total `'#'` marks for the lock and the key combined.\n",
    "\n",
    "We'll parse the schematics into paragraphs, where each paragraph is a list of lines."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 313,
   "id": "f5971853-7139-4f17-bdc5-6c51e12a928d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Puzzle input ➜ 3999 strs:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "#####\n",
      "####.\n",
      "####.\n",
      "####.\n",
      "##.#.\n",
      "#....\n",
      ".....\n",
      "\n",
      "...\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "Parsed representation ➜ 500 lists:\n",
      "────────────────────────────────────────────────────────────────────────────────────────────────────\n",
      "['#####', '####.', '####.', '####.', '##.#.', '#....', '.....']\n",
      "['#####', '####.', '##.#.', '##.#.', '.#.#.', '.#.#.', '.....']\n",
      "['.....', '.....', '#..#.', '#..#.', '##.##', '#####', '#####']\n",
      "['#####', '###.#', '#.#.#', '#.#.#', '#.#..', '#....', '.....']\n",
      "['#####', '##.#.', '#..#.', '#..#.', '#..#.', '#..#.', '.....']\n",
      "['#####', '#####', '#####', '#.##.', '..##.', '...#.', '.....']\n",
      "['#####', '#.###', '...#.', '.....', '.....', '.....', '.....']\n",
      "['.....', '.....', '.....', '.#.#.', '##.#.', '#####', '#####']\n",
      "...\n"
     ]
    }
   ],
   "source": [
    "schematics = parse(25, lines, sections=paragraphs)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3bece291-f0e6-463a-9ac9-401563c5184b",
   "metadata": {},
   "source": [
    "### Part 1: How many unique lock/key pairs fit together without overlapping in any column?\n",
    "\n",
    "This looks pretty easy:\n",
    "- The function `count_fits` will compute the answer. First it separates the schematics into locks and keys, transforming each one into a list of column heights. Then it counts how many key/lock  combinations fit, trying every possibility.\n",
    "- The function `column_heights` takes a schematic, which is a list of rows, and applies the transpose, `T(schematic)`, to get a list of columns. Then it uses `count` to count the number of `'#'` characters in each column.\n",
    "- The function `can_fit` takes takes two lists of column counts and determines if any column has more than 7 total `'#'` characters.\n",
    "\n",
    "For example, the first lock is:\n",
    "\n",
    "     ['#####', '####.', '####.', '####.', '##.#.', '#....', '.....']\n",
    "\n",
    "We transpose that to get a list of columns, \n",
    "\n",
    "     ('######.', '#####..', '####...', '#####..', '#......')\n",
    "\n",
    "and count the number of `'#'` characters in each column:\n",
    "\n",
    "     [6, 5, 4, 5, 1]\n",
    "\n",
    "Here is the code:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 315,
   "id": "5302ac58-91fc-475a-83d9-cea91457df3b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def count_fits(schematics) -> List:\n",
    "    \"\"\"Try all key/lock combinations and count how many fit each other.\"\"\"\n",
    "    locks = [column_heights(s) for s in schematics if s[0] == '#####']\n",
    "    keys  = [column_heights(s) for s in schematics if s[0] != '#####']\n",
    "    return quantify(can_fit(key, lock) for lock in locks for key in keys)\n",
    "    \n",
    "def column_heights(schematic) -> List[int]:\n",
    "    \"\"\"A counter of {column_number: (number of '#' in that column)}.\"\"\"\n",
    "    return [column.count('#') for column in T(schematic)] # Remember, `T` is transpose\n",
    "    \n",
    "def can_fit(key: Ints, lock: Ints): \n",
    "    \"\"\"The key can fit the lock if the sum of the '#' count in each column is <= 7.\"\"\"\n",
    "    return all(lock[c] + key[c] <= 7 for c in range(len(lock)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 316,
   "id": "89c28b74-ed31-4bb5-b463-7177952a95ae",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Puzzle 25.1:   .021 seconds, answer 3196              ok"
      ]
     },
     "execution_count": 316,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "answer(25.1, 3196, lambda:\n",
    "       count_fits(schematics))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce1c8e04-5297-4798-969d-3cc9210bfd9a",
   "metadata": {},
   "source": [
    "And with that, **we're done!** \n",
    "\n",
    "Thanks, [**Eric Wastl**](https://adventofcode.com/2024/about), and congratulations for ten years of AoC!\n",
    "\n",
    "<img src=\"https://files.mastodon.social/media_attachments/files/113/714/790/660/920/471/small/c34a34c48bad3d94.jpg\" width=400>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3e78ac0f-5866-4620-8114-1b05b5c44de1",
   "metadata": {},
   "source": [
    "# Summary\n",
    "\n",
    "Here are all the puzzle answers and timings. I got all the puzzles correct! And I did it before midnight (my time) on December 25th, a rarity for me. \n",
    "\n",
    "The median run time is about 5 milliseconds, with 3 puzzles taking over a second, but none taking 2 seconds (barely!). I didn't count the time that `parse` takes, but that is less than a millisecond per day. Some people in the Rust subreddit were talking about completing the puzzles in less than 10 seconds of run time. I managed to do that, even with Python's slow interpreter rather than [Rust](https://www.rust-lang.org/)'s fast compiler. But others were talking about doing all *10 years* of puzzles in less than 10 seconds, and I can't compete with that."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 319,
   "id": "34813fc9-a000-4cd8-88ae-692851b3242c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Puzzle  1.1:   .000 seconds, answer 1830467           ok\n",
      "Puzzle  1.2:   .000 seconds, answer 26674158          ok\n",
      "Puzzle  2.1:   .000 seconds, answer 257               ok\n",
      "Puzzle  2.2:   .002 seconds, answer 328               ok\n",
      "Puzzle  3.1:   .001 seconds, answer 156388521         ok\n",
      "Puzzle  3.2:   .000 seconds, answer 75920122          ok\n",
      "Puzzle  4.1:   .021 seconds, answer 2401              ok\n",
      "Puzzle  4.2:   .015 seconds, answer 1822              ok\n",
      "Puzzle  5.1:   .001 seconds, answer 5762              ok\n",
      "Puzzle  5.2:   .001 seconds, answer 4130              ok\n",
      "Puzzle  6.1:   .001 seconds, answer 5329              ok\n",
      "Puzzle  6.2:  1.932 seconds, answer 2162              ok\n",
      "Puzzle  7.1:   .014 seconds, answer 1985268524462     ok\n",
      "Puzzle  7.2:   .586 seconds, answer 150077710195188   ok\n",
      "Puzzle  8.1:   .002 seconds, answer 220               ok\n",
      "Puzzle  8.2:   .003 seconds, answer 813               ok\n",
      "Puzzle  9.1:   .019 seconds, answer 6332189866718     ok\n",
      "Puzzle  9.2:   .021 seconds, answer 6353648390778     ok\n",
      "Puzzle 10.1:   .005 seconds, answer 744               ok\n",
      "Puzzle 10.2:   .006 seconds, answer 1651              ok\n",
      "Puzzle 11.1:   .002 seconds, answer 194482            ok\n",
      "Puzzle 11.2:   .059 seconds, answer 232454623677743   ok\n",
      "Puzzle 12.1:   .050 seconds, answer 1402544           ok\n",
      "Puzzle 12.2:   .043 seconds, answer 862486            ok\n",
      "Puzzle 13.1:   .000 seconds, answer 29598             ok\n",
      "Puzzle 13.2:   .000 seconds, answer 93217456941970    ok\n",
      "Puzzle 14.1:   .000 seconds, answer 216027840         ok\n",
      "Puzzle 14.2:  1.802 seconds, answer 6876              ok\n",
      "Puzzle 15.1:   .028 seconds, answer 1563092           ok\n",
      "Puzzle 15.2:   .041 seconds, answer 1582688           ok\n",
      "Puzzle 16.1:   .146 seconds, answer 103512            ok\n",
      "Puzzle 16.2:   .837 seconds, answer 554               ok\n",
      "Puzzle 17.1:   .000 seconds, answer 2,1,0,1,7,2,5,0,3 ok\n",
      "Puzzle 17.2:   .004 seconds, answer 267265166222235   ok\n",
      "Puzzle 18.1:   .014 seconds, answer 344               ok\n",
      "Puzzle 18.2:   .031 seconds, answer 46,18             ok\n",
      "Puzzle 19.1:   .004 seconds, answer 242               ok\n",
      "Puzzle 19.2:   .180 seconds, answer 595975512785325   ok\n",
      "Puzzle 20.1:   .022 seconds, answer 1343              ok\n",
      "Puzzle 20.2:   .737 seconds, answer 982891            ok\n",
      "Puzzle 21.1:   .000 seconds, answer 205160            ok\n",
      "Puzzle 21.2:   .004 seconds, answer 252473394928452   ok\n",
      "Puzzle 22.1:   .313 seconds, answer 14273043166       ok\n",
      "Puzzle 22.2:  1.108 seconds, answer 1667              ok\n",
      "Puzzle 23.1:   .001 seconds, answer 1170              ok\n",
      "Puzzle 23.2:   .003 seconds, answer bo,dd,eq,ik,lo,lu,ph,ro,rr,rw,uo,wx,yg ok\n",
      "Puzzle 24.1:   .001 seconds, answer 36035961805936    ok\n",
      "Puzzle 24.2:   .000 seconds, answer jqf,mdd,skh,wpd,wts,z11,z19,z37 ok\n",
      "Puzzle 25.1:   .021 seconds, answer 3196              ok\n",
      "\n",
      "Correct: 49/49\n",
      "\n",
      "Time in seconds: 0.005 median, 0.165 mean, 8.084 total.\n"
     ]
    }
   ],
   "source": [
    "summary(answers)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
